summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am6
-rw-r--r--sql/cache_manager.cc150
-rw-r--r--sql/cache_manager.h61
-rw-r--r--sql/field.cc4
-rw-r--r--sql/field.h4
-rw-r--r--sql/filesort.cc505
-rw-r--r--sql/ha_innodb.cc8
-rw-r--r--sql/ha_myisam.h2
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item.cc66
-rw-r--r--sql/item.h29
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_strfunc.cc22
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/item_sum.cc71
-rw-r--r--sql/item_sum.h31
-rw-r--r--sql/log.cc168
-rw-r--r--sql/log_event.cc80
-rw-r--r--sql/mini_client.cc84
-rw-r--r--sql/mysql_priv.h5
-rw-r--r--sql/mysqld.cc63
-rw-r--r--sql/opt_range.cc8
-rw-r--r--sql/protocol.h26
-rw-r--r--sql/protocol_cursor.cc143
-rw-r--r--sql/records.cc89
-rw-r--r--sql/repl_failsafe.cc11
-rw-r--r--sql/set_var.cc16
-rw-r--r--sql/slave.cc206
-rw-r--r--sql/slave.h91
-rw-r--r--sql/sql_acl.cc26
-rw-r--r--sql/sql_base.cc13
-rw-r--r--sql/sql_class.h54
-rw-r--r--sql/sql_delete.cc17
-rw-r--r--sql/sql_derived.cc7
-rw-r--r--sql/sql_insert.cc28
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_repl.cc41
-rw-r--r--sql/sql_select.cc69
-rw-r--r--sql/sql_select.h39
-rw-r--r--sql/sql_show.cc6
-rw-r--r--sql/sql_sort.h33
-rw-r--r--sql/sql_table.cc18
-rw-r--r--sql/sql_udf.cc2
-rw-r--r--sql/sql_union.cc18
-rw-r--r--sql/sql_update.cc12
-rw-r--r--sql/sql_yacc.yy8
-rw-r--r--sql/structs.h1
-rw-r--r--sql/table.cc6
-rw-r--r--sql/table.h22
-rw-r--r--sql/uniques.cc10
-rw-r--r--sql/unireg.h15
55 files changed, 1456 insertions, 968 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index b1d9149ddf4..a4858ab2b38 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -83,9 +83,9 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
- mini_client.cc mini_client_errors.c \
+ mini_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
- gstream.cc spatial.cc sql_help.cc
+ gstream.cc spatial.cc sql_help.cc protocol_cursor.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
@@ -102,6 +102,8 @@ AM_YFLAGS = -d
link_sources:
rm -f mini_client_errors.c
@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
+ rm -f pack.c
+ @LN_CP_F@ ../sql-common/pack.c pack.c
gen_lex_hash.o: gen_lex_hash.cc lex.h
$(CXXCOMPILE) -c $(INCLUDES) $<
diff --git a/sql/cache_manager.cc b/sql/cache_manager.cc
deleted file mode 100644
index 307fe331e5c..00000000000
--- a/sql/cache_manager.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-/* 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 */
-
-#ifdef __GNUC__
-#pragma implementation /* gcc: Class implementation */
-#endif
-
-#include <my_global.h>
-#include <my_sys.h>
-#include "cache_manager.h"
-
-/*
- cache_manager.cc
- -----------------------------------------------------------------------
- The cache_manager class manages a number of blocks (which are allocatable
- units of memory).
- -----------------------------------------------------------------------
-*/
-
-#define HEADER_LENGTH ALIGN_SIZE(8)
-#define SUFFIX_LENGTH 4
-
-#define ALLOC_MASK 0x3FFFFFFFL
-#define FREE_BIT (1L << 31)
-#define LOCK_BIT (1L << 30)
-#define SMALLEST_BLOCK 32
-
-
-
-/*
-** Internal Methods
-** --------------------
-*/
-
-
-/* list manipulation methods */
-void *cache_manager::init_list(void)
-{
-
-return;
-}
-
-
-void *cache_manager::link_into_abs(void *ptr)
-{
- for (int i(0); (*abs_list)[i] != NULL; i++);
-
- (*abs_list)[i] = ptr;
-
- return (abs_list)[i]; // ???
-}
-
-
-
-bool *cache_manager::unlink_from_abs(void *ptr)
-{
- (*ptr) = NULL;
-
-return;
-}
-
-
-
-/* memory allocation methods */
-void *cache_manager::find_in_llist(uint)
-{
-
-return;
-}
-
-
-void cache_manager::defrag(void)
-{
- printf("Defragging: ..........");
-
- return;
-}
-
-
-
-/*
-** Public Methods
-** ------------------
-*/
-
-cache_manager::cache_manager(uint size)
-{
- base_ptr = my_malloc(size, MY_WME); /* MY_WME = write mesg on err */
-
- return;
-}
-
-
-cache_manager::~cache_manager(void)
-{
- free(base_ptr);
- delete base_ptr;
-
- return;
-}
-
-
-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)))
- {
- //defrag();
- if (!(llist = find_in_llist(size)))
- return 0; /* return null pointer, buffer exhausted! */
- }
- 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;
-}
-
-
-void cache_manager::dealloc(void)
-{
- printf("Deallocating: ..........\n");
-
- return;
-}
-
-
-
-void cache_manager::clear(void)
-{
- // reset the internal linked list, forgetting all pointers to mem blks
-
- return;
-}
diff --git a/sql/cache_manager.h b/sql/cache_manager.h
deleted file mode 100644
index d422a86ea8e..00000000000
--- a/sql/cache_manager.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* 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 */
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-#ifndef _CACHE_MANAGER_H_
-#define _CACHE_MANAGER_H_
-#endif
-
-/*
- cache_manager.h
- -----------------------------------------------------------------------
- The cache_manager class manages a number of blocks (which are allocatable
- units of memory).
- -----------------------------------------------------------------------
-*/
-
-
-
-class cache_manager {
- void **abs_list; /* List holding block abstraction ptrs */
-
- typedef struct free_blks {
- struct free_blks *next, **prev;
- uint Size;
- } FREE_BLKS;
- FREE_BLKS *base_ptr; /* Pointer to newly allocated sys mem */
-
-
- /* list manipulation methods */
- void *link_into_abs(void *); /* Return an abstract pointer to blk */
- bool *unlink_from_abs(void *); /* Used to dealloc a blk */
- void *find_in_fblist(uint); /* */
-
- /* memory allocation methods */
- void defrag(void); /* Defragment the cache */
- bool *init_blk(void *); /* Return a pointer to new list */
-
- public:
- cache_manager(uint); /* Get allocation of size from system */
- ~cache_manager(void); /* Destructor; return the cache */
-
- void *alloc(uint); /* Alloc size bytes from the cache */
- bool *dealloc(void *); /* Deallocate blocks (with *ptr_arg) */
- void clear(void); /* Clear the cache */
-};
diff --git a/sql/field.cc b/sql/field.cc
index 0ea206a4fa7..3695268a888 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5462,9 +5462,9 @@ create_field::create_field(Field *old_field,Field *orig_field)
char buff[MAX_FIELD_WIDTH],*pos;
String tmp(buff,sizeof(buff), charset);
- /* Get the value from record[2] (the default value row) */
+ /* Get the value from default_values */
my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2);
- orig_field->move_field(diff); // Points now at record[2]
+ orig_field->move_field(diff); // Points now at default_values
bool is_null=orig_field->is_real_null();
orig_field->val_str(&tmp,&tmp);
orig_field->move_field(-diff); // Back to record[0]
diff --git a/sql/field.h b/sql/field.h
index 7334ff66dd8..80bfc516ef7 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -57,7 +57,7 @@ public:
GEOM_GEOMETRYCOLLECTION = 7
};
enum imagetype { itRAW, itMBR};
-
+
utype unireg_check;
uint32 field_length; // Length of field
uint16 flags;
@@ -83,7 +83,7 @@ public:
virtual void reset_fields() {}
virtual void set_default()
{
- my_ptrdiff_t offset = table->default_values() - table->record[0];
+ my_ptrdiff_t offset = table->default_values - table->record[0];
memcpy(ptr, ptr + offset, pack_length());
if (null_ptr)
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 4c2ba1e1a59..a3d24cd9242 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,4 +1,5 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+/* 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
@@ -51,6 +52,10 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count);
static uint sortlength(SORT_FIELD *sortorder, uint s_length,
bool *multi_byte_charset);
+static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
+ uint sortlength, uint *plength);
+static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
+ byte *buff);
/*
Creates a set of pointers that can be used to read the rows
@@ -82,16 +87,48 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
DBUG_PUSH(""); /* No DBUG here */
#endif
- outfile= table->io_cache;
+ outfile= table->sort.io_cache;
my_b_clear(&tempfile);
my_b_clear(&buffpek_pointers);
buffpek=0;
sort_keys= (uchar **) NULL;
error= 1;
bzero((char*) &param,sizeof(param));
+ param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
param.ref_length= table->file->ref_length;
- param.sort_length= (sortlength(sortorder,s_length, &multi_byte_charset)+
- param.ref_length);
+ param.addon_field= 0;
+ param.addon_length= 0;
+ if (!(table->tmp_table || table->fulltext_searched))
+ {
+ /*
+ Get the descriptors of all fields whose values are appended
+ to sorted fields and get its total length in param.spack_length.
+ */
+ param.addon_field= get_addon_fields(thd, table->field,
+ param.sort_length,
+ &param.addon_length);
+ }
+ table->sort.addon_buf= 0;
+ table->sort.addon_length= param.addon_length;
+ table->sort.addon_field= param.addon_field;
+ table->sort.unpack= unpack_addon_fields;
+ if (param.addon_field)
+ {
+ param.res_length= param.addon_length;
+ if (!(table->sort.addon_buf= (byte *) my_malloc(param.addon_length,
+ MYF(MY_WME))))
+ goto err;
+ }
+ else
+ {
+ param.res_length= param.ref_length;
+ /*
+ The reference to the record is considered
+ as an additional sorted field
+ */
+ param.sort_length+= param.ref_length;
+ }
+ param.rec_length= param.sort_length+param.addon_length;
param.max_rows= max_rows;
if (select && select->quick)
@@ -115,7 +152,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
records=table->file->estimate_number_of_rows();
selected_records_file= 0;
}
- if (param.sort_length == param.ref_length && records > param.max_rows)
+ if (param.rec_length == param.ref_length && records > param.max_rows)
records=param.max_rows; /* purecov: inspected */
if (multi_byte_charset &&
@@ -127,9 +164,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
while (memavl >= min_sort_memory)
{
ulong old_memavl;
- ulong keys= memavl/(param.sort_length+sizeof(char*));
+ ulong keys= memavl/(param.rec_length+sizeof(char*));
param.keys=(uint) min(records+1, keys);
- if ((sort_keys= (uchar **) make_char_array(param.keys, param.sort_length,
+ if ((sort_keys= (uchar **) make_char_array(param.keys, param.rec_length,
MYF(0))))
break;
old_memavl=memavl;
@@ -176,8 +213,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
Use also the space previously used by string pointers in sort_buffer
for temporary key storage.
*/
- param.keys=((param.keys*(param.sort_length+sizeof(char*))) /
- param.sort_length-1);
+ param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
+ param.rec_length-1);
maxbuffer--; // Offset from 0
if (merge_many_buff(&param,(uchar*) sort_keys,buffpek,&maxbuffer,
&tempfile))
@@ -225,6 +262,22 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
} /* filesort */
+void filesort_free_buffers(TABLE *table)
+{
+ if (table->sort.record_pointers)
+ {
+ my_free((gptr) table->sort.record_pointers,MYF(0));
+ table->sort.record_pointers=0;
+ }
+ if (table->sort.addon_buf)
+ {
+ my_free((char *) table->sort.addon_buf, MYF(0));
+ my_free((char *) table->sort.addon_field, MYF(MY_ALLOW_ZERO_PTR));
+ table->sort.addon_buf=0;
+ table->sort.addon_field=0;
+ }
+}
+
/* Make a array of string pointers */
static char **make_char_array(register uint fields, uint length, myf my_flag)
@@ -356,8 +409,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
DBUG_RETURN(HA_POS_ERROR);
idx=0;
- if (param->ref_length == param->sort_length &&
- my_b_tell(tempfile)/param->sort_length >= param->max_rows)
+ if (param->ref_length == param->rec_length &&
+ my_b_tell(tempfile)/param->rec_length >= param->max_rows)
{
/*
We are writing the result index file and have found all
@@ -385,7 +438,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
DBUG_RETURN(my_b_inited(tempfile) ?
- (ha_rows) (my_b_tell(tempfile)/param->sort_length) :
+ (ha_rows) (my_b_tell(tempfile)/param->rec_length) :
idx);
} /* find_all_keys */
@@ -394,29 +447,30 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
static int
write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
- IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
+ IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
- uint sort_length;
+ uint sort_length, rec_length;
uchar **end;
BUFFPEK buffpek;
DBUG_ENTER("write_keys");
- sort_length=param->sort_length;
+ sort_length= param->sort_length;
+ rec_length= param->rec_length;
#ifdef MC68000
quicksort(sort_keys,count,sort_length);
#else
- my_string_ptr_sort((gptr) sort_keys,(uint) count,sort_length);
+ my_string_ptr_sort((gptr) sort_keys, (uint) count, sort_length);
#endif
if (!my_b_inited(tempfile) &&
- open_cached_file(tempfile,mysql_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
- MYF(MY_WME)))
- goto err; /* purecov: inspected */
- buffpek.file_pos=my_b_tell(tempfile);
+ open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
+ MYF(MY_WME)))
+ goto err; /* purecov: inspected */
+ buffpek.file_pos= my_b_tell(tempfile);
if ((ha_rows) count > param->max_rows)
- count=(uint) param->max_rows; /* purecov: inspected */
+ count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
- if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length))
+ if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length))
goto err;
if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek)))
goto err;
@@ -505,10 +559,10 @@ static void make_sortkey(register SORTPARAM *param,
}
else
{
- my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
- bzero((char *)to+length,diff);
+ my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
+ bzero((char *)to+length,diff);
}
- break;
+ break;
}
case INT_RESULT:
{
@@ -577,29 +631,56 @@ static void make_sortkey(register SORTPARAM *param,
else
to+= sort_field->length;
}
- memcpy((byte*) to,ref_pos,(size_s) param->ref_length);/* Save filepos last */
+
+ if (param->addon_field)
+ {
+ /*
+ Save field values appended to sorted fields.
+ First null bit indicators are appended then field values follow.
+ In this implementation we use fixed layout for field values -
+ the same for all records.
+ */
+ SORT_ADDON_FIELD *addonf= param->addon_field;
+ uchar *nulls= to;
+ DBUG_ASSERT(addonf);
+ bzero((char *) nulls, addonf->offset);
+ to+= addonf->offset;
+ for ( ; (field= addonf->field) ; addonf++)
+ {
+ if (addonf->null_bit && field->is_null())
+ nulls[addonf->null_offset]|= addonf->null_bit;
+ else
+ field->pack((char *) to, field->ptr);
+ to+= addonf->length;
+ }
+ }
+ else
+ {
+ /* Save filepos last */
+ memcpy((byte*) to, ref_pos, (size_s) param->ref_length);
+ }
return;
}
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
{
- uint offset,ref_length;
+ uint offset,res_length;
byte *to;
DBUG_ENTER("save_index");
- my_string_ptr_sort((gptr) sort_keys,(uint) count,param->sort_length);
- ref_length=param->ref_length;
- offset=param->sort_length-ref_length;
+ my_string_ptr_sort((gptr) sort_keys, (uint) count, param->sort_length);
+ res_length= param->res_length;
+ offset= param->rec_length-res_length;
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows;
- if (!(to=param->sort_form->record_pointers=
- (byte*) my_malloc(ref_length*count,MYF(MY_WME))))
- DBUG_RETURN(1); /* purecov: inspected */
- for (uchar **end=sort_keys+count ; sort_keys != end ; sort_keys++)
+ if (!(to= param->sort_form->sort.record_pointers=
+ (byte*) my_malloc(res_length*count, MYF(MY_WME))))
+ DBUG_RETURN(1); /* purecov: inspected */
+ for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
{
- memcpy(to,*sort_keys+offset,ref_length);
- to+=ref_length;
+ memcpy(to, *sort_keys+offset, res_length);
+ to+= res_length;
}
DBUG_RETURN(0);
}
@@ -654,7 +735,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
/* This returns (uint) -1 if something goes wrong */
uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
- uint sort_length)
+ uint rec_length)
{
register uint count;
uint length;
@@ -662,33 +743,35 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
{
if (my_pread(fromfile->file,(byte*) buffpek->base,
- (length= sort_length*count),buffpek->file_pos,MYF_RW))
+ (length= rec_length*count),buffpek->file_pos,MYF_RW))
return((uint) -1); /* purecov: inspected */
buffpek->key=buffpek->base;
buffpek->file_pos+= length; /* New filepos */
buffpek->count-= count;
buffpek->mem_count= count;
}
- return (count*sort_length);
+ return (count*rec_length);
} /* read_to_buffer */
- /* Merge buffers to one buffer */
+/*
+ Merge buffers to one buffer
+*/
int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
- IO_CACHE *to_file, uchar *sort_buffer,
- BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
- int flag)
+ IO_CACHE *to_file, uchar *sort_buffer,
+ BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
+ int flag)
{
int error;
- uint sort_length,offset;
+ uint rec_length,sort_length,res_length,offset;
ulong maxcount;
ha_rows max_rows,org_max_rows;
my_off_t to_start_filepos;
uchar *strpos;
BUFFPEK *buffpek,**refpek;
QUEUE queue;
- qsort2_cmp cmp;
+ qsort2_cmp cmp;
volatile bool *killed= &current_thd->killed;
bool not_killable;
DBUG_ENTER("merge_buffers");
@@ -697,29 +780,32 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (param->not_killable)
{
killed= &not_killable;
- not_killable=0;
+ not_killable= 0;
}
error=0;
- offset=(sort_length=param->sort_length)-param->ref_length;
- maxcount=(ulong) (param->keys/((uint) (Tb-Fb) +1));
- to_start_filepos=my_b_tell(to_file);
- strpos=(uchar*) sort_buffer;
- org_max_rows=max_rows=param->max_rows;
-
- if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
- (queue_compare)
- (cmp=get_ptr_compare(sort_length)),(void*) &sort_length))
- DBUG_RETURN(1); /* purecov: inspected */
+ rec_length= param->rec_length;
+ res_length= param->res_length;
+ sort_length= param->sort_length;
+ offset= rec_length-res_length;
+ maxcount= (ulong) (param->keys/((uint) (Tb-Fb) +1));
+ to_start_filepos= my_b_tell(to_file);
+ strpos= (uchar*) sort_buffer;
+ org_max_rows=max_rows= param->max_rows;
+
+ if (init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
+ (queue_compare) (cmp= get_ptr_compare(sort_length)),
+ (void*) &sort_length))
+ DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
buffpek->base= strpos;
- buffpek->max_keys=maxcount;
- strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek,
- sort_length));
+ buffpek->max_keys= maxcount;
+ strpos+= (uint) (error= (int) read_to_buffer(from_file, buffpek,
+ rec_length));
if (error == -1)
- goto err; /* purecov: inspected */
- queue_insert(&queue,(byte*) buffpek);
+ goto err; /* purecov: inspected */
+ queue_insert(&queue, (byte*) buffpek);
}
if (param->unique_buff)
@@ -732,98 +818,101 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
This is safe as we know that there is always more than one element
in each block to merge (This is guaranteed by the Unique:: algorithm
*/
- buffpek=(BUFFPEK*) queue_top(&queue);
- memcpy(param->unique_buff, buffpek->key, sort_length);
- if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
+ buffpek= (BUFFPEK*) queue_top(&queue);
+ memcpy(param->unique_buff, buffpek->key, rec_length);
+ if (my_b_write(to_file, (byte*) buffpek->key, rec_length))
{
- error=1; goto err; /* purecov: inspected */
+ error=1; goto err; /* purecov: inspected */
}
- buffpek->key+=sort_length;
+ buffpek->key+= rec_length;
buffpek->mem_count--;
if (!--max_rows)
{
- error=0; /* purecov: inspected */
- goto end; /* purecov: inspected */
+ error= 0; /* purecov: inspected */
+ goto end; /* purecov: inspected */
}
- queue_replaced(&queue); // Top element has been used
+ queue_replaced(&queue); // Top element has been used
}
else
- cmp=0; // Not unique
+ cmp= 0; // Not unique
while (queue.elements > 1)
{
if (*killed)
{
- error=1; goto err; /* purecov: inspected */
+ error= 1; goto err; /* purecov: inspected */
}
for (;;)
{
- buffpek=(BUFFPEK*) queue_top(&queue);
- if (cmp) // Remove duplicates
+ buffpek= (BUFFPEK*) queue_top(&queue);
+ if (cmp) // Remove duplicates
{
- if (!(*cmp)(&sort_length, &(param->unique_buff),
- (uchar**) &buffpek->key))
- goto skip_duplicate;
- memcpy(param->unique_buff, (uchar*) buffpek->key,sort_length);
+ if (!(*cmp)(&sort_length, &(param->unique_buff),
+ (uchar**) &buffpek->key))
+ goto skip_duplicate;
+ memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
}
if (flag == 0)
{
- if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
- {
- error=1; goto err; /* purecov: inspected */
- }
+ if (my_b_write(to_file,(byte*) buffpek->key, rec_length))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
}
else
{
- WRITE_REF(to_file,(byte*) buffpek->key+offset);
+ if (my_b_write(to_file, (byte*) buffpek->key+offset, res_length))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
}
if (!--max_rows)
{
- error=0; /* purecov: inspected */
- goto end; /* purecov: inspected */
+ error= 0; /* purecov: inspected */
+ goto end; /* purecov: inspected */
}
skip_duplicate:
- buffpek->key+=sort_length;
+ buffpek->key+= rec_length;
if (! --buffpek->mem_count)
{
- if (!(error=(int) read_to_buffer(from_file,buffpek,
- sort_length)))
- {
- uchar *base=buffpek->base;
- ulong max_keys=buffpek->max_keys;
-
- VOID(queue_remove(&queue,0));
-
- /* Put room used by buffer to use in other buffer */
- for (refpek= (BUFFPEK**) &queue_top(&queue);
- refpek <= (BUFFPEK**) &queue_end(&queue);
- refpek++)
- {
- buffpek= *refpek;
- if (buffpek->base+buffpek->max_keys*sort_length == base)
- {
- buffpek->max_keys+=max_keys;
- break;
- }
- else if (base+max_keys*sort_length == buffpek->base)
- {
- buffpek->base=base;
- buffpek->max_keys+=max_keys;
- break;
- }
- }
- break; /* One buffer have been removed */
- }
- else if (error == -1)
- goto err; /* purecov: inspected */
+ if (!(error= (int) read_to_buffer(from_file,buffpek,
+ rec_length)))
+ {
+ uchar *base= buffpek->base;
+ ulong max_keys= buffpek->max_keys;
+
+ VOID(queue_remove(&queue,0));
+
+ /* Put room used by buffer to use in other buffer */
+ for (refpek= (BUFFPEK**) &queue_top(&queue);
+ refpek <= (BUFFPEK**) &queue_end(&queue);
+ refpek++)
+ {
+ buffpek= *refpek;
+ if (buffpek->base+buffpek->max_keys*rec_length == base)
+ {
+ buffpek->max_keys+= max_keys;
+ break;
+ }
+ else if (base+max_keys*rec_length == buffpek->base)
+ {
+ buffpek->base= base;
+ buffpek->max_keys+= max_keys;
+ break;
+ }
+ }
+ break; /* One buffer have been removed */
+ }
+ else if (error == -1)
+ goto err; /* purecov: inspected */
}
- queue_replaced(&queue); /* Top element has been replaced */
+ queue_replaced(&queue); /* Top element has been replaced */
}
}
- buffpek=(BUFFPEK*) queue_top(&queue);
+ buffpek= (BUFFPEK*) queue_top(&queue);
buffpek->base= sort_buffer;
- buffpek->max_keys=param->keys;
+ buffpek->max_keys= param->keys;
/*
As we know all entries in the buffer are unique, we only have to
@@ -833,7 +922,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
{
if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key))
{
- buffpek->key+=sort_length; // Remove duplicate
+ buffpek->key+= rec_length; // Remove duplicate
--buffpek->mem_count;
}
}
@@ -841,37 +930,40 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
do
{
if ((ha_rows) buffpek->mem_count > max_rows)
- { /* Don't write too many records */
- buffpek->mem_count=(uint) max_rows;
- buffpek->count=0; /* Don't read more */
+ { /* Don't write too many records */
+ buffpek->mem_count= (uint) max_rows;
+ buffpek->count= 0; /* Don't read more */
}
- max_rows-=buffpek->mem_count;
+ max_rows-= buffpek->mem_count;
if (flag == 0)
{
if (my_b_write(to_file,(byte*) buffpek->key,
- (sort_length*buffpek->mem_count)))
+ (rec_length*buffpek->mem_count)))
{
- error=1; goto err; /* purecov: inspected */
+ error= 1; goto err; /* purecov: inspected */
}
}
else
{
register uchar *end;
strpos= buffpek->key+offset;
- for (end=strpos+buffpek->mem_count*sort_length;
- strpos != end ;
- strpos+=sort_length)
- {
- WRITE_REF(to_file,strpos);
+ for (end= strpos+buffpek->mem_count*rec_length ;
+ strpos != end ;
+ strpos+= rec_length)
+ {
+ if (my_b_write(to_file, (byte *) strpos, res_length))
+ {
+ error=1; goto err;
+ }
}
}
}
- while ((error=(int) read_to_buffer(from_file,buffpek,sort_length))
- != -1 && error != 0);
+ while ((error=(int) read_to_buffer(from_file,buffpek, rec_length))
+ != -1 && error != 0);
end:
- lastbuff->count=min(org_max_rows-max_rows,param->max_rows);
- lastbuff->file_pos=to_start_filepos;
+ lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
+ lastbuff->file_pos= to_start_filepos;
err:
delete_queue(&queue);
DBUG_RETURN(error);
@@ -925,7 +1017,6 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
sortorder->need_strxnfrm= 0;
if (sortorder->field)
{
-
if (sortorder->field->type() == FIELD_TYPE_BLOB)
sortorder->length= thd->variables.max_sort_length;
else
@@ -947,7 +1038,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
if (use_strnxfrm((cs=sortorder->item->charset())))
- {
+ {
sortorder->length= sortorder->length*cs->strxfrm_multiply;
sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1;
@@ -982,6 +1073,148 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
/*
+ Get descriptors of fields appended to sorted fields and
+ calculate its total length
+
+ SYNOPSIS
+ get_addon_fields()
+ thd Current thread
+ ptabfields Array of references to the table fields
+ sortlength Total length of sorted fields
+ plength out: Total length of appended fields
+
+ DESCRIPTION
+ The function first finds out what fields are used in the result set.
+ Then it calculates the length of the buffer to store the values of
+ these fields together with the value of sort values.
+ If the calculated length is not greater than max_length_for_sort_data
+ the function allocates memory for an array of descriptors containing
+ layouts for the values of the non-sorted fields in the buffer and
+ fills them.
+
+ NOTES
+ The null bits for the appended values are supposed to be put together
+ and stored the buffer just ahead of the value of the first field.
+
+ RETURN
+ Pointer to the layout descriptors for the appended fields, if any
+ NULL - if we do not store field values with sort data.
+*/
+
+static SORT_ADDON_FIELD *
+get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
+{
+ Field **pfield;
+ Field *field;
+ SORT_ADDON_FIELD *addonf;
+ uint length= 0;
+ uint fields= 0;
+ uint null_fields= 0;
+
+ /*
+ If there is a reference to a field in the query add it
+ to the the set of appended fields.
+ Note for future refinement:
+ This this a too strong condition.
+ Actually we need only the fields referred in the
+ result set. And for some of them it makes sense to use
+ the values directly from sorted fields.
+ */
+ *plength= 0;
+ /*
+ The following statement is added to avoid sorting in alter_table.
+ The fact is the filter 'field->query_id != thd->query_id'
+ doesn't work for alter table
+ */
+ if (thd->lex.sql_command != SQLCOM_SELECT)
+ return 0;
+ for (pfield= ptabfield; (field= *pfield) ; pfield++)
+ {
+ if (field->query_id != thd->query_id)
+ continue;
+ if (field->flags & BLOB_FLAG)
+ return 0;
+ length+= field->max_packed_col_length(field->pack_length());
+ if (field->maybe_null())
+ null_fields++;
+ fields++;
+ }
+ if (!fields)
+ return 0;
+ length+= (null_fields+7)/8;
+
+ if (length+sortlength > thd->variables.max_length_for_sort_data ||
+ !(addonf= (SORT_ADDON_FIELD *) my_malloc(sizeof(SORT_ADDON_FIELD)*
+ (fields+1), MYF(MY_WME))))
+ return 0;
+
+ *plength= length;
+ length= (null_fields+7)/8;
+ null_fields= 0;
+ for (pfield= ptabfield; (field= *pfield) ; pfield++)
+ {
+ if (field->query_id != thd->query_id)
+ continue;
+ addonf->field= field;
+ addonf->offset= length;
+ if (field->maybe_null())
+ {
+ addonf->null_offset= null_fields/8;
+ addonf->null_bit= 1<<(null_fields & 7);
+ null_fields++;
+ }
+ else
+ {
+ addonf->null_offset= 0;
+ addonf->null_bit= 0;
+ }
+ addonf->length= field->max_packed_col_length(field->pack_length());
+ length+= addonf->length;
+ addonf++;
+ }
+ addonf->field= 0; // Put end marker
+
+ DBUG_PRINT("info",("addon_length: %d",length));
+ return (addonf-fields);
+}
+
+
+/*
+ Copy (unpack) values appended to sorted fields from a buffer back to
+ their regular positions specified by the Field::ptr pointers.
+
+ SYNOPSIS
+ unpack_addon_fields()
+ addon_field Array of descriptors for appended fields
+ buff Buffer which to unpack the value from
+
+ NOTES
+ The function is supposed to be used only as a callback function
+ when getting field values for the sorted result set.
+
+ RETURN
+ void.
+*/
+
+static void
+unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
+{
+ Field *field;
+ SORT_ADDON_FIELD *addonf= addon_field;
+
+ for ( ; (field= addonf->field) ; addonf++)
+ {
+ if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
+ {
+ field->set_null();
+ continue;
+ }
+ field->set_notnull();
+ field->unpack(field->ptr, (char *) buff+addonf->offset);
+ }
+}
+
+/*
** functions to change a double or float to a sortable string
** The following should work for IEEE
*/
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index aa5d88bf177..4f955d8f79e 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -916,11 +916,11 @@ innobase_commit_low(
/* Update the replication position info inside InnoDB */
trx->mysql_master_log_file_name
- = active_mi->rli.master_log_name;
+ = active_mi->rli.group_master_log_name;
trx->mysql_master_log_pos = ((ib_longlong)
- (active_mi->rli.master_log_pos +
- active_mi->rli.event_len +
- active_mi->rli.pending));
+ (active_mi->rli.group_master_log_pos +
+ active_mi->rli.event_len
+ ));
}
#endif /* HAVE_REPLICATION */
trx_commit_for_mysql(trx);
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 5dc294b3b9f..154429ecc0d 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -46,7 +46,7 @@ class ha_myisam: public handler
ha_myisam(TABLE *table): handler(table), file(0),
int_table_flags(HA_READ_RND_SAME | HA_KEYPOS_TO_RNDPOS | HA_LASTKEY_ORDER |
HA_NULL_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
- HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY),
+ HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY | HA_HAS_GEOMETRY),
enable_activate_all_index(1)
{}
~ha_myisam() {}
diff --git a/sql/handler.cc b/sql/handler.cc
index 762e07eec64..e4317506ed7 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -34,6 +34,8 @@
#endif
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
+#else
+#define innobase_query_caching_of_table_permitted(X,Y,Z) 1
#endif
#include <myisampack.h>
#include <errno.h>
@@ -877,7 +879,7 @@ int handler::delete_all_rows()
return (my_errno=HA_ERR_WRONG_COMMAND);
}
-bool handler::caching_allowed(THD* thd, char* table_key,
+bool handler::caching_allowed(THD* thd, char* table_key,
uint key_length, uint8 cache_type)
{
if (cache_type == HA_CACHE_TBL_ASKTRANSACT)
diff --git a/sql/handler.h b/sql/handler.h
index 557fec0de0e..8c23a3625e0 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -48,6 +48,7 @@
#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */
#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber;
It returns a position to ha_r_rnd */
+#define HA_HAS_GEOMETRY 16
#define HA_NO_INDEX 32 /* No index needed for next/prev */
#define HA_KEY_READ_WRONG_STR 64 /* keyread returns converted strings */
#define HA_NULL_KEY 128 /* One can have keys with NULL */
diff --git a/sql/item.cc b/sql/item.cc
index 2bb9fa62ff4..bd2b929cee7 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -349,7 +349,7 @@ table_map Item_field::used_tables() const
{
if (field->table->const_table)
return 0; // const item
- return (depended_from ? RAND_TABLE_BIT : field->table->map);
+ return (depended_from ? OUTER_REF_TABLE_BIT : field->table->map);
}
Item *Item_field::get_tmp_table_item(THD *thd)
@@ -772,9 +772,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(last= sl)->get_table_list(), &where,
0)) != not_found_field)
break;
- if ((refer= find_item_in_list(this, sl->item_list, &counter,
- REPORT_EXCEPT_NOT_FOUND)) !=
- (Item **)not_found_item)
+ if (sl->item_list.elements &&
+ ((refer= find_item_in_list(this, sl->item_list, &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item))
break;
if (sl->master_unit()->first_select()->linkage ==
DERIVED_TABLE_TYPE)
@@ -1388,8 +1389,8 @@ bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list,
if (!def_field)
return 1;
memcpy(def_field, field_arg->field, field_arg->field->size_of());
- def_field->move_field(def_field->table->default_values() -
- def_field->table->record[0]);
+ def_field->move_field(def_field->table->default_values -
+ def_field->table->record[0]);
set_field(def_field);
return 0;
}
@@ -1406,6 +1407,59 @@ void Item_default_value::print(String *str)
str->append(')');
}
+bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
+{
+ return item->type() == INSERT_VALUE_ITEM &&
+ ((Item_default_value *)item)->arg->eq(arg, binary_cmp);
+}
+
+
+bool Item_insert_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items)
+{
+ bool res= arg->fix_fields(thd, table_list, items);
+ if (res)
+ return res;
+ /*
+ arg->type() can be only REF_ITEM or FIELD_ITEM as arg is
+ a simple_ident in sql_yacc.yy
+ */
+ if (arg->type() == REF_ITEM)
+ {
+ Item_ref *ref= (Item_ref *)arg;
+ if (ref->ref[0]->type() != FIELD_ITEM)
+ {
+ return 1;
+ }
+ arg= ref->ref[0];
+ }
+ Item_field *field_arg= (Item_field *)arg;
+ if (field_arg->field->table->insert_values)
+ {
+ Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
+ if (!def_field)
+ return 1;
+ memcpy(def_field, field_arg->field, field_arg->field->size_of());
+ def_field->move_field(def_field->table->insert_values -
+ def_field->table->record[0]);
+ set_field(def_field);
+ }
+ else
+ {
+ Field *field=field_arg->field;
+ /* charset doesn't matter here, it's to avoid sigsegv only */
+ set_field(new Field_null(0,0,Field::NONE,field->field_name,field->table,
+ default_charset_info));
+ }
+ return 0;
+}
+
+void Item_insert_value::print(String *str)
+{
+ str->append("VALUE(");
+ arg->print(str);
+ str->append(')');
+}
+
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
diff --git a/sql/item.h b/sql/item.h
index 6603e11166b..111892df688 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -34,13 +34,13 @@ public:
enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,
COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
- PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
- FIELD_VARIANCE_ITEM, CONST_ITEM,
+ PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
+ FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
- enum coercion { COER_COERCIBLE=3, COER_IMPLICIT=2,
- COER_NOCOLL=1, COER_EXPLICIT=0 };
+ enum coercion { COER_COERCIBLE=3, COER_IMPLICIT=2,
+ COER_NOCOLL=1, COER_EXPLICIT=0 };
String str_value; /* used to store value */
my_string name; /* Name from select */
@@ -201,6 +201,7 @@ public:
bool is_null() { return field->is_null(); }
Item *get_tmp_table_item(THD *thd);
friend class Item_default_value;
+ friend class Item_insert_value;
};
class Item_null :public Item
@@ -734,7 +735,7 @@ public:
Item *arg;
Item_default_value() :
Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {}
- Item_default_value(Item *a) :
+ Item_default_value(Item *a) :
Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
@@ -754,6 +755,24 @@ public:
table_map used_tables() const { return (table_map)0L; }
};
+class Item_insert_value : public Item_field
+{
+public:
+ Item *arg;
+ Item_insert_value(Item *a) :
+ Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
+ bool eq(const Item *item, bool binary_cmp) const;
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ void set_outer_resolving() { arg->set_outer_resolving(); }
+ void print(String *str);
+ virtual bool basic_const_item() const { return true; }
+ int save_in_field(Field *field, bool no_conversions)
+ {
+ return Item_field::save_in_field(field, no_conversions);
+ }
+ table_map used_tables() const { return (table_map)0L; }
+};
+
class Item_cache: public Item
{
table_map used_table_map;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 0f21cf5a774..7cc07690fcc 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -346,7 +346,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
if (cache->cols() == 1)
{
if (args[0]->used_tables())
- cache->set_used_tables(RAND_TABLE_BIT);
+ cache->set_used_tables(OUTER_REF_TABLE_BIT);
else
cache->set_used_tables(0);
}
@@ -356,7 +356,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
for (uint i= 0; i < n; i++)
{
if (args[0]->el(i)->used_tables())
- ((Item_cache *)cache->el(i))->set_used_tables(RAND_TABLE_BIT);
+ ((Item_cache *)cache->el(i))->set_used_tables(OUTER_REF_TABLE_BIT);
else
((Item_cache *)cache->el(i))->set_used_tables(0);
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 56e3eb2cb5f..07ec66e9f9d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1457,11 +1457,13 @@ String *Item_func_user::val_str(String *str)
{
THD *thd=current_thd;
CHARSET_INFO *cs= default_charset();
- const char *host=thd->host ? thd->host : thd->ip ? thd->ip : "";
+ const char *host= thd->host_or_ip;
+ uint res_length;
+
// For system threads (e.g. replication SQL thread) user may be empty
if (!thd->user)
return &empty_string;
- uint32 res_length=(strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen;
+ res_length= (strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen;
if (str->alloc(res_length))
{
@@ -2943,7 +2945,7 @@ String *Item_func_compress::val_str(String *str)
*/
ulong new_size= (ulong)((res->length()*120)/100)+12;
- buffer.realloc((uint32)new_size + 4);
+ buffer.realloc((uint32)new_size + 4 + 1);
Byte *body= ((Byte*)buffer.c_ptr()) + 4;
if ((err= compress(body, &new_size,
@@ -2954,8 +2956,18 @@ String *Item_func_compress::val_str(String *str)
null_value= 1;
return 0;
}
-
- int4store(buffer.c_ptr(),res->length() & 0x3FFFFFFF);
+
+ char *tmp= buffer.c_ptr(); // int4store is a macro; avoid side effects
+ int4store(tmp, res->length() & 0x3FFFFFFF);
+
+ /* This is for the stupid char fields which trim ' ': */
+ char *last_char= ((char*)body)+new_size-1;
+ if (*last_char == ' ')
+ {
+ *++last_char= '.';
+ new_size++;
+ }
+
buffer.length((uint32)new_size + 4);
return &buffer;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 6c0b799b4de..c749fba616f 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -128,7 +128,7 @@ void Item_subselect::fix_length_and_dec()
inline table_map Item_subselect::used_tables() const
{
return (table_map) (engine->dependent() ? 1L :
- (engine->uncacheable() ? RAND_TABLE_BIT : 0L));
+ (engine->uncacheable() ? OUTER_REF_TABLE_BIT : 0L));
}
Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 653f71e3d79..11c850f9d5f 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -993,7 +993,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
int error;
/*
The first item->rec_offset bytes are taken care of with
- restore_record(table,2) in setup()
+ restore_record(table,default_values) in setup()
*/
memcpy(buf + item->rec_offset, key, item->tree->size_of_element);
if ((error = item->table->file->write_row(buf)))
@@ -1075,7 +1075,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
void* cmp_arg;
// to make things easier for dump_leaf if we ever have to dump to MyISAM
- restore_record(table,2);
+ restore_record(table,default_values);
if (table->fields == 1)
{
@@ -1348,7 +1348,7 @@ static int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
byte* key2)
{
Item_func_group_concat* item= (Item_func_group_concat*)arg;
- for (int i= 0; i<item->arg_count_field; i++)
+ for (uint i= 0; i < item->arg_count_field; i++)
{
Item *field_item= item->expr[i];
Field *field= field_item->tmp_table_field();
@@ -1377,7 +1377,7 @@ static int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
static int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
{
Item_func_group_concat* item= (Item_func_group_concat*)arg;
- for (int i=0; i<item->arg_count_order; i++)
+ for (uint i=0; i < item->arg_count_order; i++)
{
ORDER *order_item= item->order[i];
Item *item= *order_item->item;
@@ -1404,9 +1404,10 @@ static int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
*/
-static int group_concat_key_cmp_with_distinct_and_order(void* arg, byte* key1, byte* key2)
+static int group_concat_key_cmp_with_distinct_and_order(void* arg,
+ byte* key1,
+ byte* key2)
{
- Item_func_group_concat* item= (Item_func_group_concat*)arg;
if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
return 0;
return(group_concat_key_cmp_with_order(arg,key1,key2));
@@ -1427,7 +1428,7 @@ static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
tmp.length(0);
- for (int i= 0; i < group_concat_item->arg_show_fields; i++)
+ for (uint i= 0; i < group_concat_item->arg_show_fields; i++)
{
Item *show_item= group_concat_item->expr[i];
if (!show_item->const_item())
@@ -1481,13 +1482,13 @@ static int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
is_separator - string value of separator
*/
-Item_func_group_concat::Item_func_group_concat(int is_distinct,
+Item_func_group_concat::Item_func_group_concat(bool is_distinct,
List<Item> *is_select,
SQL_LIST *is_order,
String *is_separator)
:Item_sum(), tmp_table_param(0), warning_available(false),
- separator(is_separator), tree(&tree_base), table(0), distinct(is_distinct),
- tree_mode(0), count_cut_values(0)
+ separator(is_separator), tree(&tree_base), table(0),
+ count_cut_values(0), tree_mode(0), distinct(is_distinct)
{
original= 0;
quick_group= 0;
@@ -1506,39 +1507,31 @@ Item_func_group_concat::Item_func_group_concat(int is_distinct,
expr - arg_count_field
order - arg_count_order
*/
- args= (Item**)sql_alloc(sizeof(Item*)*(arg_count+arg_count_order+arg_count_field)+
- sizeof(ORDER*)*arg_count_order);
+ args= (Item**) sql_alloc(sizeof(Item*)*(arg_count+arg_count_order+
+ arg_count_field)+
+ sizeof(ORDER*)*arg_count_order);
if (!args)
- {
- my_error(ER_OUTOFMEMORY,MYF(0));
- }
+ return; // thd->fatal is set
expr= args;
expr+= arg_count+arg_count_order;
- if (arg_count_order)
- {
- order= (ORDER**)(expr + arg_count_field);
- }
- /*
- fill args items of show and sort
- */
+
+ /* fill args items of show and sort */
int i= 0;
List_iterator_fast<Item> li(*is_select);
Item *item_select;
- while ((item_select= li++))
- {
+ for ( ; (item_select= li++) ; i++)
args[i]= expr[i]= item_select;
- i++;
- }
-
- if (order)
+
+ if (arg_count_order)
{
- uint j= 0;
- for (ORDER *order_item= (ORDER*)is_order->first;
+ i= 0;
+ order= (ORDER**)(expr + arg_count_field);
+ for (ORDER *order_item= (ORDER*) is_order->first;
order_item != NULL;
order_item= order_item->next)
{
- order[j++]= order_item;
+ order[i++]= order_item;
}
}
}
@@ -1561,8 +1554,7 @@ Item_func_group_concat::~Item_func_group_concat()
}
if (table)
free_tmp_table(thd, table);
- if (tmp_table_param)
- delete tmp_table_param;
+ delete tmp_table_param;
if (tree_mode)
delete_tree(tree);
}
@@ -1593,14 +1585,17 @@ bool Item_func_group_concat::add()
copy_funcs(tmp_table_param->items_to_copy);
bool record_is_null= TRUE;
- for (int i= 0; i < arg_show_fields; i++)
+ for (uint i= 0; i < arg_show_fields; i++)
{
Item *show_item= expr[i];
if (!show_item->const_item())
{
Field *f= show_item->tmp_table_field();
if (!f->is_null())
+ {
record_is_null= FALSE;
+ break;
+ }
}
}
if (record_is_null)
@@ -1631,7 +1626,7 @@ void Item_func_group_concat::reset_field()
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- int i; /* for loop variable */
+ uint i; /* for loop variable */
if (!thd->allow_sum_func)
{
@@ -1641,11 +1636,11 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
thd->allow_sum_func= 0;
maybe_null= 0;
- for (uint ui= 0 ; ui < arg_count ; ui++)
+ for (i= 0 ; i < arg_count ; i++)
{
- if (args[ui]->fix_fields(thd, tables, args + ui) || args[ui]->check_cols(1))
+ if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
return 1;
- maybe_null |= args[ui]->maybe_null;
+ maybe_null |= args[i]->maybe_null;
}
for (i= 0 ; i < arg_count_field ; i++)
{
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 1b3e993fffc..37d7e7f79d0 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -643,21 +643,20 @@ class Item_func_group_concat : public Item_sum
public:
String result;
String *separator;
- uint show_elements;
TREE tree_base;
TREE *tree;
TABLE *table;
- int arg_count_order;
- int arg_count_field;
- int arg_show_fields;
- int distinct;
Item **expr;
ORDER **order;
- bool tree_mode;
- int count_cut_values;
+ TABLE_LIST *tables_list;
ulong group_concat_max_len;
+ uint show_elements;
+ uint arg_count_order;
+ uint arg_count_field;
+ uint arg_show_fields;
+ uint count_cut_values;
+ bool tree_mode, distinct;
bool warning_for_row;
- TABLE_LIST *tables_list;
bool always_null;
/*
Following is 0 normal object and pointer to original one for copy
@@ -665,7 +664,7 @@ class Item_func_group_concat : public Item_sum
*/
Item_func_group_concat *original;
- Item_func_group_concat(int is_distinct,List<Item> *is_select,
+ Item_func_group_concat(bool is_distinct,List<Item> *is_select,
SQL_LIST *is_order,String *is_separator);
Item_func_group_concat(THD *thd, Item_func_group_concat &item)
@@ -675,20 +674,20 @@ class Item_func_group_concat : public Item_sum
warning(item.warning),
warning_available(item.warning_available),
separator(item.separator),
- show_elements(item.show_elements),
tree(item.tree),
table(item.table),
+ expr(item.expr),
+ order(item.order),
+ tables_list(item.tables_list),
+ group_concat_max_len(item.group_concat_max_len),
+ show_elements(item.show_elements),
arg_count_order(item.arg_count_order),
arg_count_field(item.arg_count_field),
arg_show_fields(item.arg_show_fields),
- distinct(item.distinct),
- expr(item.expr),
- order(item.order),
- tree_mode(0),
count_cut_values(item.count_cut_values),
- group_concat_max_len(item.group_concat_max_len),
+ tree_mode(0),
+ distinct(item.distinct),
warning_for_row(item.warning_for_row),
- tables_list(item.tables_list),
original(&item)
{
quick_group = 0;
diff --git a/sql/log.cc b/sql/log.cc
index 51b1c572601..c9e20bc0cc9 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -592,24 +592,32 @@ err:
/*
- Delete the current log file, remove it from index file and start on next
+ Delete relay log files prior to rli->group_relay_log_name
+ (i.e. all logs which are not involved in a non-finished group
+ (transaction)), remove them from the index file and start on next relay log.
SYNOPSIS
purge_first_log()
- rli Relay log information
-
+ rli Relay log information
+ included If false, all relay logs that are strictly before
+ rli->group_relay_log_name are deleted ; if true, the latter is
+ deleted too (i.e. all relay logs
+ read by the SQL slave thread are deleted).
+
NOTE
- This is only called from the slave-execute thread when it has read
- all commands from a log and want to switch to a new log.
- - When this happens, we should never be in an active transaction as
- a transaction is always written as a single block to the binary log.
+ all commands from a relay log and want to switch to a new relay log.
+ - When this happens, we can be in an active transaction as
+ a transaction can span over two relay logs
+ (although it is always written as a single block to the master's binary
+ log, hence cannot span over two master's binary logs).
IMPLEMENTATION
- Protects index file with LOCK_index
- - Delete first log file,
- - Copy all file names after this one to the front of the index file
+ - Delete relevant relay log files
+ - Copy all file names after these ones to the front of the index file
- If the OS has truncate, truncate the file, else fill it with \n'
- - Read the first file name from the index file and store in rli->linfo
+ - Read the next file name from the index file and store in rli->linfo
RETURN VALUES
0 ok
@@ -620,66 +628,68 @@ err:
#ifdef HAVE_REPLICATION
-int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
+int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
{
int error;
DBUG_ENTER("purge_first_log");
- /*
- Test pre-conditions.
-
- Assume that we have previously read the first log and
- stored it in rli->relay_log_name
- */
DBUG_ASSERT(is_open());
DBUG_ASSERT(rli->slave_running == 1);
- DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name));
- DBUG_ASSERT(rli->linfo.index_file_offset ==
- strlen(rli->relay_log_name) + 1);
+ DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
- /* We have already processed the relay log, so it's safe to delete it */
- my_delete(rli->relay_log_name, MYF(0));
pthread_mutex_lock(&LOCK_index);
- if (copy_up_file_and_fill(&index_file, rli->linfo.index_file_offset))
- {
- error= LOG_INFO_IO;
- goto err;
- }
+ pthread_mutex_lock(&rli->log_space_lock);
+ rli->relay_log.purge_logs(rli->group_relay_log_name, included,
+ 0, 0, &rli->log_space_total);
+ // Tell the I/O thread to take the relay_log_space_limit into account
+ rli->ignore_log_space_limit= 0;
+ pthread_mutex_unlock(&rli->log_space_lock);
/*
- Update the space counter used by all relay logs
Ok to broadcast after the critical region as there is no risk of
the mutex being destroyed by this thread later - this helps save
context switches
*/
- pthread_mutex_lock(&rli->log_space_lock);
- rli->log_space_total -= rli->relay_log_pos;
- //tell the I/O thread to take the relay_log_space_limit into account
- rli->ignore_log_space_limit= 0;
- pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
/*
Read the next log file name from the index file and pass it back to
the caller
+ If included is true, we want the first relay log;
+ otherwise we want the one after event_relay_log_name.
*/
- if ((error=find_log_pos(&rli->linfo, NullS, 0 /*no mutex*/)))
+ if ((included && (error=find_log_pos(&rli->linfo, NullS, 0))) ||
+ (!included &&
+ ((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
+ (error=find_next_log(&rli->linfo, 0)))))
{
char buff[22];
- sql_print_error("next log error: %d offset: %s log: %s",
- error,
- llstr(rli->linfo.index_file_offset,buff),
- rli->linfo.log_file_name);
+ sql_print_error("next log error: %d offset: %s log: %s included: %d",
+ error,
+ llstr(rli->linfo.index_file_offset,buff),
+ rli->group_relay_log_name,
+ included);
goto err;
}
+
/*
- Reset position to current log. This involves setting both of the
- position variables:
+ Reset rli's coordinates to the current log.
*/
- rli->relay_log_pos = BIN_LOG_HEADER_SIZE;
- rli->pending = 0;
- strmake(rli->relay_log_name,rli->linfo.log_file_name,
- sizeof(rli->relay_log_name)-1);
+ rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
+ strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->event_relay_log_name)-1);
+
+ /*
+ If we removed the rli->group_relay_log_name file,
+ we must update the rli->group* coordinates, otherwise do not touch it as the
+ group's execution is not finished (e.g. COMMIT not executed)
+ */
+ if (included)
+ {
+ rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
+ strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->group_relay_log_name)-1);
+ }
/* Store where we are in the new file for the execution thread */
flush_relay_log_info(rli);
@@ -693,13 +703,14 @@ err:
Update log index_file
*/
-int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
+int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
{
if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
return LOG_INFO_IO;
// now update offsets in index file for running threads
- adjust_linfo_offsets(log_info->index_file_start_offset);
+ if (need_update_threads)
+ adjust_linfo_offsets(log_info->index_file_start_offset);
return 0;
}
@@ -708,9 +719,13 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
SYNOPSIS
purge_logs()
- thd Thread pointer
- to_log Delete all log file name before this file. This file is not
- deleted
+ to_log Delete all log file name before this file.
+ included If true, to_log is deleted too.
+ need_mutex
+ need_update_threads If we want to update the log coordinates of
+ all threads. False for relay logs, true otherwise.
+ freed_log_space If not null, decrement this variable of
+ the amount of log space freed
NOTES
If any of the logs before the deleted one is in use,
@@ -722,31 +737,60 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
LOG_INFO_EOF to_log not found
*/
-int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
+int MYSQL_LOG::purge_logs(const char *to_log,
+ bool included,
+ bool need_mutex,
+ bool need_update_threads,
+ ulonglong *decrease_log_space)
{
int error;
+ bool exit_loop= 0;
LOG_INFO log_info;
DBUG_ENTER("purge_logs");
+ DBUG_PRINT("info",("to_log= %s",to_log));
if (no_rotate)
DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE);
- pthread_mutex_lock(&LOCK_index);
+ if (need_mutex)
+ pthread_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
goto err;
/*
- File name exists in index file; Delete until we find this file
+ File name exists in index file; delete until we find this file
or a file that is used.
*/
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
- while (strcmp(to_log,log_info.log_file_name) &&
- !log_in_use(log_info.log_file_name))
+ while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
+ !log_in_use(log_info.log_file_name))
{
- /* It's not fatal even if we can't delete a log file */
- my_delete(log_info.log_file_name, MYF(0));
- if (find_next_log(&log_info, 0))
+ ulong tmp;
+ LINT_INIT(tmp);
+ if (decrease_log_space) //stat the file we want to delete
+ {
+ MY_STAT s;
+ if (my_stat(log_info.log_file_name,&s,MYF(0)))
+ tmp= s.st_size;
+ else
+ {
+ /*
+ If we could not stat, we can't know the amount
+ of space that deletion will free. In most cases,
+ deletion won't work either, so it's not a problem.
+ */
+ tmp= 0;
+ }
+ }
+ /*
+ It's not fatal if we can't delete a log file ;
+ if we could delete it, take its size into account
+ */
+ DBUG_PRINT("info",("purging %s",log_info.log_file_name));
+ if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
+ *decrease_log_space-= tmp;
+ if (find_next_log(&log_info, 0) || exit_loop)
break;
}
@@ -754,10 +798,11 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
If we get killed -9 here, the sysadmin would have to edit
the log index file after restart - otherwise, this should be safe
*/
- error= update_log_index(&log_info);
+ error= update_log_index(&log_info, need_update_threads);
err:
- pthread_mutex_unlock(&LOCK_index);
+ if (need_mutex)
+ pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -779,7 +824,7 @@ err:
LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
*/
-int MYSQL_LOG::purge_logs_before_date(THD* thd, time_t purge_time)
+int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
{
int error;
LOG_INFO log_info;
@@ -816,7 +861,7 @@ int MYSQL_LOG::purge_logs_before_date(THD* thd, time_t purge_time)
If we get killed -9 here, the sysadmin would have to edit
the log index file after restart - otherwise, this should be safe
*/
- error= update_log_index(&log_info);
+ error= update_log_index(&log_info, 1);
err:
pthread_mutex_unlock(&LOCK_index);
@@ -1269,7 +1314,7 @@ err:
{
long purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
- error= purge_logs_before_date(current_thd, purge_time);
+ error= purge_logs_before_date(purge_time);
}
#endif
@@ -1534,7 +1579,6 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
If you don't do it this way, you will get a deadlock in THD::awake()
*/
-
void MYSQL_LOG:: wait_for_update(THD* thd)
{
safe_mutex_assert_owner(&LOCK_log);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d4efb65bf42..39db264d898 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -310,11 +310,36 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
*/
if (rli)
{
- if (rli->inside_transaction)
- rli->inc_pending(get_event_len());
+ /*
+ If in a transaction, and if the slave supports transactions,
+ just inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
+ (not OPTION_NOT_AUTOCOMMIT) as transactions are logged
+ with BEGIN/COMMIT, not with SET AUTOCOMMIT= .
+
+ CAUTION: opt_using_transactions means
+ innodb || bdb ; suppose the master supports InnoDB and BDB,
+ but the slave supports only BDB, problems
+ will arise:
+ - suppose an InnoDB table is created on the master,
+ - then it will be MyISAM on the slave
+ - but as opt_using_transactions is true, the slave will believe he is
+ transactional with the MyISAM table. And problems will come when one
+ does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at BEGIN
+ whereas there has not been any rollback). This is the problem of
+ using opt_using_transactions instead of a finer
+ "does the slave support _the_transactional_handler_used_on_the_master_".
+
+ More generally, we'll have problems when a query mixes a transactional
+ handler and MyISAM and STOP SLAVE is issued in the middle of the
+ "transaction". START SLAVE will resume at BEGIN while the MyISAM table has
+ already been updated.
+
+ */
+ if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
+ rli->inc_event_relay_log_pos(get_event_len());
else
{
- rli->inc_pos(get_event_len(),log_pos);
+ rli->inc_group_relay_log_pos(get_event_len(),log_pos);
flush_relay_log_info(rli);
}
}
@@ -878,9 +903,13 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
thd->db = rewrite_db((char*)db);
/*
- InnoDB internally stores the master log position it has processed so far;
- position to store is really pos + pending + event_len
- since we must store the pos of the END of the current log event
+ InnoDB internally stores the master log position it has executed so far,
+ i.e. the position just after the COMMIT event.
+ When InnoDB will want to store, the positions in rli won't have
+ been updated yet, so group_master_log_* will point to old BEGIN
+ and event_master_log* will point to the beginning of current COMMIT.
+ So the position to store is event_master_log_pos + event_len
+ since we must store the pos of the END of the current log event (COMMIT).
*/
rli->event_len= get_event_len();
@@ -909,18 +938,6 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
DBUG_PRINT("query",("%s",thd->query));
mysql_parse(thd, thd->query, q_len);
- /*
- Set a flag if we are inside an transaction so that we can restart
- the transaction from the start if we are killed
-
- This will only be done if we are supporting transactional tables
- in the slave.
- */
- if (!strcmp(thd->query,"BEGIN"))
- rli->inside_transaction= opt_using_transactions;
- else if (!strcmp(thd->query,"COMMIT"))
- rli->inside_transaction=0;
-
DBUG_PRINT("info",("expected_error: %d last_errno: %d",
expected_error, thd->net.last_errno));
if ((expected_error != (actual_error= thd->net.last_errno)) &&
@@ -1776,14 +1793,15 @@ int Rotate_log_event::write_data(IO_CACHE* file)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
{
- char* log_name = rli->master_log_name;
+ char* log_name = rli->group_master_log_name;
DBUG_ENTER("Rotate_log_event::exec_event");
pthread_mutex_lock(&rli->data_lock);
memcpy(log_name, new_log_ident, ident_len+1);
- rli->master_log_pos = pos;
- rli->relay_log_pos += get_event_len();
- DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos));
+ rli->group_master_log_pos = pos;
+ rli->event_relay_log_pos += get_event_len();
+ rli->group_relay_log_pos = rli->event_relay_log_pos;
+ DBUG_PRINT("info", ("group_master_log_pos: %d", (ulong) rli->group_master_log_pos));
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
flush_relay_log_info(rli);
@@ -1905,7 +1923,7 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
thd->next_insert_id = val;
break;
}
- rli->inc_pending(get_event_len());
+ rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
#endif
@@ -1967,7 +1985,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
- rli->inc_pending(get_event_len());
+ rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
#endif // !MYSQL_CLIENT
@@ -2199,7 +2217,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
e.update_hash(val, val_len, type, charset, Item::COER_NOCOLL);
free_root(&thd->mem_root,0);
- rli->inc_pending(get_event_len());
+ rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
#endif // !MYSQL_CLIENT
@@ -2241,7 +2259,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
pthread_mutex_lock(&mi->data_lock);
pthread_mutex_lock(&rli->data_lock);
master_host_len = strlen(mi->host);
- master_log_len = strlen(rli->master_log_name);
+ master_log_len = strlen(rli->group_master_log_name);
// on OOM, just do not initialize the structure and print the error
if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
MYF(MY_WME))))
@@ -2249,9 +2267,9 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
memcpy(master_host, mi->host, master_host_len + 1);
master_log = master_host + master_host_len + 1;
- memcpy(master_log, rli->master_log_name, master_log_len + 1);
+ memcpy(master_log, rli->group_master_log_name, master_log_len + 1);
master_port = mi->port;
- master_pos = rli->master_log_pos;
+ master_pos = rli->group_master_log_pos;
DBUG_PRINT("info", ("master_log: %s pos: %d", master_log,
(ulong) master_pos));
}
@@ -2381,19 +2399,19 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
int Stop_log_event::exec_event(struct st_relay_log_info* rli)
{
// do not clean up immediately after rotate event
- if (rli->master_log_pos > BIN_LOG_HEADER_SIZE)
+ if (rli->group_master_log_pos > BIN_LOG_HEADER_SIZE)
{
close_temporary_tables(thd);
cleanup_load_tmpdir();
}
/*
We do not want to update master_log pos because we get a rotate event
- before stop, so by now master_log_name is set to the next log.
+ before stop, so by now group_master_log_name is set to the next log.
If we updated it, we will have incorrect master coordinates and this
could give false triggers in MASTER_POS_WAIT() that we have reached
the target position when in fact we have not.
*/
- rli->inc_pos(get_event_len(), 0);
+ rli->inc_group_relay_log_pos(get_event_len(), 0);
flush_relay_log_info(rli);
return 0;
}
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
index db3a51712f2..afcee5fbb02 100644
--- a/sql/mini_client.cc
+++ b/sql/mini_client.cc
@@ -23,6 +23,7 @@
*/
#include <my_global.h>
+
#ifdef HAVE_EXTERNAL_CLIENT
/* my_pthread must be included early to be able to fix things */
@@ -80,8 +81,6 @@ void mc_end_server(MYSQL *mysql);
static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to);
static void mc_free_old_query(MYSQL *mysql);
static int mc_send_file_to_server(MYSQL *mysql, const char *filename);
-static my_ulonglong mc_net_field_length_ll(uchar **packet);
-static ulong mc_net_field_length(uchar **packet);
static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
ulong *lengths);
static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
@@ -1085,15 +1084,15 @@ int mc_mysql_read_query_result(MYSQL *mysql)
mc_free_old_query(mysql); /* Free old result */
get_info:
pos=(uchar*) mysql->net.read_pos;
- if ((field_count= mc_net_field_length(&pos)) == 0)
+ if ((field_count= net_field_length(&pos)) == 0)
{
- mysql->affected_rows= mc_net_field_length_ll(&pos);
- mysql->insert_id= mc_net_field_length_ll(&pos);
+ mysql->affected_rows= net_field_length_ll(&pos);
+ mysql->insert_id= net_field_length_ll(&pos);
if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
{
mysql->server_status=uint2korr(pos); pos+=2;
}
- if (pos < mysql->net.read_pos+length && mc_net_field_length(&pos))
+ if (pos < mysql->net.read_pos+length && net_field_length(&pos))
mysql->info=(char*) pos;
DBUG_RETURN(0);
}
@@ -1107,7 +1106,7 @@ get_info:
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
- mysql->extra_info= mc_net_field_length_ll(&pos); /* Maybe number of rec */
+ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=mc_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
DBUG_RETURN(-1);
if (!(mysql->fields=mc_unpack_fields(fields,&mysql->field_alloc,
@@ -1190,68 +1189,6 @@ err:
DBUG_RETURN(result);
}
-
-/* Get the length of next field. Change parameter to point at fieldstart */
-static ulong mc_net_field_length(uchar **packet)
-{
- reg1 uchar *pos= *packet;
- if (*pos < 251)
- {
- (*packet)++;
- return (ulong) *pos;
- }
- if (*pos == 251)
- {
- (*packet)++;
- return NULL_LENGTH;
- }
- if (*pos == 252)
- {
- (*packet)+=3;
- return (ulong) uint2korr(pos+1);
- }
- if (*pos == 253)
- {
- (*packet)+=4;
- return (ulong) uint3korr(pos+1);
- }
- (*packet)+=9; /* Must be 254 when here */
- return (ulong) uint4korr(pos+1);
-}
-
-/* Same as above, but returns ulonglong values */
-
-static my_ulonglong mc_net_field_length_ll(uchar **packet)
-{
- reg1 uchar *pos= *packet;
- if (*pos < 251)
- {
- (*packet)++;
- return (my_ulonglong) *pos;
- }
- if (*pos == 251)
- {
- (*packet)++;
- return (my_ulonglong) NULL_LENGTH;
- }
- if (*pos == 252)
- {
- (*packet)+=3;
- return (my_ulonglong) uint2korr(pos+1);
- }
- if (*pos == 253)
- {
- (*packet)+=4;
- return (my_ulonglong) uint3korr(pos+1);
- }
- (*packet)+=9; /* Must be 254 when here */
-#ifdef NO_CLIENT_LONGLONG
- return (my_ulonglong) uint4korr(pos+1);
-#else
- return (my_ulonglong) uint8korr(pos+1);
-#endif
-}
-
/* Read all rows (fields or data) from server */
static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
@@ -1301,7 +1238,7 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
to= (char*) (cur->data+fields+1);
for (field=0 ; field < fields ; field++)
{
- if ((len=(ulong) mc_net_field_length(&cp)) == NULL_LENGTH)
+ if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
{ /* null field */
cur->data[field] = 0;
}
@@ -1342,7 +1279,8 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
{
uint field;
ulong pkt_len,len;
- uchar *pos,*prev_pos;
+ uchar *pos;
+ uchar *prev_pos;
if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
return -1;
@@ -1352,7 +1290,7 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
pos=mysql->net.read_pos;
for (field=0 ; field < fields ; field++)
{
- if ((len=(ulong) mc_net_field_length(&pos)) == NULL_LENGTH)
+ if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
{ /* null field */
row[field] = 0;
*lengths++=0;
@@ -1365,7 +1303,7 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
}
if (prev_pos)
*prev_pos=0; /* Terminate prev field */
- prev_pos=pos;
+ prev_pos= pos;
}
row[field]=(char*) prev_pos+1; /* End of last field */
*prev_pos=0; /* Terminate last field */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 4203d440667..4ecccbf4511 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -30,7 +30,7 @@
#undef write /* remove pthread.h macro definition for EMX */
#endif
-typedef ulong table_map; /* Used for table bits in join */
+typedef ulonglong table_map; /* Used for table bits in join */
typedef ulong key_map; /* Used for finding keys */
typedef ulong key_part_map; /* Used for finding key parts */
@@ -721,7 +721,7 @@ extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size;
extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days;
-
+extern my_bool relay_log_purge;
extern uint test_flags,select_errors,ha_open_options;
extern uint protocol_version,dropping_tables;
extern uint delay_key_write_options;
@@ -846,6 +846,7 @@ void end_read_record(READ_RECORD *info);
ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
uint s_length, SQL_SELECT *select,
ha_rows max_rows, ha_rows *examined_rows);
+void filesort_free_buffers(TABLE *table);
void change_double_for_sort(double nr,byte *to);
int get_quick_record(SQL_SELECT *select);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ea0311bafc6..6907da7d8e1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -314,7 +314,7 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool lower_case_table_names, opt_old_rpl_compat;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
-my_bool opt_console= 0;
+my_bool opt_console= 0, opt_bdb, opt_innodb;
volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
@@ -442,6 +442,7 @@ const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF";
ulong rpl_recovery_rank=0;
+my_bool relay_log_purge=1;
my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL;
MY_TMPDIR mysql_tmpdir_list;
@@ -2208,7 +2209,7 @@ static int init_server_components()
{
long purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
- mysql_bin_log.purge_logs_before_date(current_thd, purge_time);
+ mysql_bin_log.purge_logs_before_date(purge_time);
}
#endif
}
@@ -3400,7 +3401,7 @@ enum options
OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
OPT_BDB_HOME, OPT_BDB_LOG,
OPT_BDB_TMP, OPT_BDB_NOSYNC,
- OPT_BDB_LOCK, OPT_BDB_SKIP,
+ OPT_BDB_LOCK, OPT_BDB,
OPT_BDB_NO_RECOVER, OPT_BDB_SHARED,
OPT_MASTER_HOST, OPT_MASTER_USER,
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
@@ -3430,7 +3431,7 @@ enum options
OPT_INNODB_FLUSH_METHOD,
OPT_INNODB_FAST_SHUTDOWN,
OPT_SAFE_SHOW_DB,
- OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC,
+ OPT_INNODB, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
@@ -3457,7 +3458,7 @@ enum options
OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE,
- OPT_MAX_JOIN_SIZE, OPT_MAX_SORT_LENGTH,
+ OPT_MAX_JOIN_SIZE, OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_SORT_LENGTH,
OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT,
@@ -3468,7 +3469,7 @@ enum options
OPT_OPEN_FILES_LIMIT,
OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE,
OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER,
- OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT,
+ OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE,
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
OPT_SORT_BUFFER, OPT_TABLE_CACHE,
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
@@ -3529,8 +3530,10 @@ struct my_option my_long_options[] =
(gptr*) &berkeley_tmpdir, (gptr*) &berkeley_tmpdir, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_BERKELEY_DB */
- {"skip-bdb", OPT_BDB_SKIP, "Don't use berkeley db (will save memory)",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"bdb", OPT_BDB, "Enable Berkeley DB (if this version of MySQL supports it). \
+Disable with --skip-bdb (will save memory)",
+ (gptr*) &opt_bdb, (gptr*) &opt_bdb, 0, GET_BOOL, NO_ARG, 1, 0, 0,
+ 0, 0, 0},
{"big-tables", OPT_BIG_TABLES,
"Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -3885,8 +3888,10 @@ struct my_option my_long_options[] =
"Start without grant tables. This gives all users FULL ACCESS to all tables!",
(gptr*) &opt_noacl, (gptr*) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
- {"skip-innodb", OPT_INNODB_SKIP, "Don't use Innodb (will save memory)",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"innodb", OPT_INNODB, "Enable InnoDB (if this version of MySQL supports it). \
+Disable with --skip-innodb (will save memory)",
+ (gptr*) &opt_innodb, (gptr*) &opt_innodb, 0, GET_BOOL, NO_ARG, 1, 0, 0,
+ 0, 0, 0},
{"skip-locking", OPT_SKIP_LOCK,
"Deprecated option, use --skip-external-locking instead",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -4159,6 +4164,11 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.max_join_size,
(gptr*) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
~0L, 1, ~0L, 0, 1, 0},
+ {"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA,
+ "Max number of bytes in sorted records",
+ (gptr*) &global_system_variables.max_length_for_sort_data,
+ (gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
+ REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
{"max_prepared_statements", OPT_MAX_PREP_STMT,
"Max number of prepared_statements for a thread",
(gptr*) &global_system_variables.max_prep_stmt_count,
@@ -4272,6 +4282,11 @@ struct my_option my_long_options[] =
(gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0},
#ifdef HAVE_REPLICATION
+ {"relay_log_purge", OPT_RELAY_LOG_PURGE,
+ "0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.",
+ (gptr*) &relay_log_purge,
+ (gptr*) &relay_log_purge, 0, GET_BOOL, NO_ARG,
+ 1, 0, 1, 0, 1, 0},
{"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT,
"Max space to use for all relay logs",
(gptr*) &relay_log_space_limit,
@@ -5016,16 +5031,32 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
berkeley_shared_data=1;
break;
#endif /* HAVE_BERKELEY_DB */
- case OPT_BDB_SKIP:
+ case OPT_BDB:
#ifdef HAVE_BERKELEY_DB
- berkeley_skip=1;
- have_berkeley_db=SHOW_OPTION_DISABLED;
+ if (opt_bdb)
+ {
+ berkeley_skip=0;
+ have_berkeley_db=SHOW_OPTION_YES;
+ }
+ else
+ {
+ berkeley_skip=1;
+ have_berkeley_db=SHOW_OPTION_DISABLED;
+ }
#endif
break;
- case OPT_INNODB_SKIP:
+ case OPT_INNODB:
#ifdef HAVE_INNOBASE_DB
- innodb_skip=1;
- have_innodb=SHOW_OPTION_DISABLED;
+ if (opt_innodb)
+ {
+ innodb_skip=0;
+ have_innodb=SHOW_OPTION_YES;
+ }
+ else
+ {
+ innodb_skip=1;
+ have_innodb=SHOW_OPTION_DISABLED;
+ }
#endif
break;
case OPT_INNODB_DATA_FILE_PATH:
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 92bab76bedd..7526772cd09 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -349,13 +349,13 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
select->head=head;
select->cond=conds;
- if (head->io_cache)
+ if (head->sort.io_cache)
{
- select->file= *head->io_cache;
+ select->file= *head->sort.io_cache;
select->records=(ha_rows) (select->file.end_of_file/
head->file->ref_length);
- my_free((gptr) (head->io_cache),MYF(0));
- head->io_cache=0;
+ my_free((gptr) (head->sort.io_cache),MYF(0));
+ head->sort.io_cache=0;
}
DBUG_RETURN(select);
}
diff --git a/sql/protocol.h b/sql/protocol.h
index 89b838ff6e4..dd644afd335 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -22,9 +22,9 @@
class i_string;
class THD;
-#ifdef EMBEDDED_LIBRARY
typedef struct st_mysql_field MYSQL_FIELD;
-#endif
+typedef struct st_mysql_rows MYSQL_ROWS;
+
class Protocol
{
protected:
@@ -135,6 +135,28 @@ public:
virtual bool store(Field *field);
};
+class Protocol_cursor :public Protocol_simple
+{
+public:
+ MEM_ROOT *alloc;
+ MYSQL_FIELD *fields;
+ MYSQL_ROWS *data;
+ MYSQL_ROWS **prev_record;
+ ulong row_count;
+
+ Protocol_cursor() {}
+ Protocol_cursor(THD *thd, MEM_ROOT *ini_alloc) :Protocol_simple(thd), alloc(ini_alloc) {}
+ bool prepare_for_send(List<Item> *item_list)
+ {
+ fields= NULL;
+ data= NULL;
+ prev_record= &data;
+ return Protocol_simple::prepare_for_send(item_list);
+ }
+ bool send_fields(List<Item> *list, uint flag);
+ bool write();
+};
+
void send_warning(THD *thd, uint sql_errno, const char *err=0);
void net_printf(THD *thd,uint sql_errno, ...);
void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc
new file mode 100644
index 00000000000..19e3bb06d74
--- /dev/null
+++ b/sql/protocol_cursor.cc
@@ -0,0 +1,143 @@
+/* Copyright (C) 2000-2003 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 */
+
+/*
+ Low level functions for storing data to be send to the MySQL client
+ The actual communction is handled by the net_xxx functions in net_serv.cc
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <mysql.h>
+
+bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
+{
+ List_iterator_fast<Item> it(*list);
+ Item *item;
+ MYSQL_FIELD *field, *client_field;
+
+ DBUG_ENTER("send_fields");
+ if (prepare_for_send(list))
+ return FALSE;
+
+ fields= (MYSQL_FIELD *)alloc_root(alloc, sizeof(MYSQL_FIELD) * field_count);
+ if (!fields)
+ goto err;
+
+ client_field= fields;
+ while ((item= it++))
+ {
+ Send_field server_field;
+ item->make_field(&server_field);
+
+ client_field->db= strdup_root(alloc, server_field.db_name);
+ client_field->table= strdup_root(alloc, server_field.table_name);
+ client_field->name= strdup_root(alloc, server_field.col_name);
+ client_field->org_table= strdup_root(alloc, server_field.org_table_name);
+ client_field->org_name= strdup_root(alloc, server_field.org_col_name);
+ client_field->length= server_field.length;
+ client_field->type= server_field.type;
+ client_field->flags= server_field.flags;
+ client_field->decimals= server_field.decimals;
+ client_field->db_length= strlen(client_field->db);
+ client_field->table_length= strlen(client_field->table);
+ client_field->name_length= strlen(client_field->name);
+ client_field->org_name_length= strlen(client_field->org_name);
+ client_field->org_table_length= strlen(client_field->org_table);
+ client_field->charsetnr= server_field.charsetnr;
+
+ if (INTERNAL_NUM_FIELD(client_field))
+ client_field->flags|= NUM_FLAG;
+
+ if (flag & 2)
+ {
+ char buff[80];
+ String tmp(buff, sizeof(buff), default_charset_info), *res;
+
+ if (!(res=item->val_str(&tmp)))
+ client_field->def= strdup_root(alloc, "");
+ else
+ client_field->def= strdup_root(alloc, tmp.ptr());
+ }
+ else
+ client_field->def=0;
+ client_field->max_length= 0;
+ ++client_field;
+ }
+
+ DBUG_RETURN(FALSE);
+ err:
+ send_error(thd, ER_OUT_OF_RESOURCES); /* purecov: inspected */
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+}
+
+/* Get the length of next field. Change parameter to point at fieldstart */
+bool Protocol_cursor::write()
+{
+ byte *cp= (byte *)packet->ptr();
+ byte *end_pos= (byte *)packet->ptr() + packet->length();
+ ulong len;
+ MYSQL_FIELD *cur_field= fields;
+ MYSQL_FIELD *fields_end= fields + field_count;
+ MYSQL_ROWS *new_record;
+ byte **data;
+ byte *to;
+
+ new_record= (MYSQL_ROWS *)alloc_root(alloc,
+ sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length());
+ if (!new_record)
+ goto err;
+ data= (byte **)(new_record + 1);
+ new_record->data= (char **)data;
+
+ to= (byte *)(fields + field_count + 1);
+
+ for (; cur_field < fields_end; ++cur_field, ++data)
+ {
+ if ((len=net_field_length((uchar **)&cp)))
+ {
+ *data= 0;
+ }
+ else
+ {
+ if ((long)len > (end_pos - cp))
+ {
+// TODO error signal send_error(thd, CR_MALFORMED_PACKET);
+ return TRUE;
+ }
+ memcpy(to,(char*) cp,len);
+ to[len]=0;
+ to+=len+1;
+ cp+=len;
+ if (cur_field->max_length < len)
+ cur_field->max_length=len;
+ }
+ }
+
+ *prev_record= new_record;
+ prev_record= &new_record->next;
+ new_record->next= NULL;
+ row_count++;
+ return FALSE;
+ err:
+// TODO error signal send_error(thd, ER_OUT_OF_RESOURCES);
+ return TRUE;
+}
+
+
diff --git a/sql/records.cc b/sql/records.cc
index 22c4d54550c..9d8627bc1fc 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -1,3 +1,4 @@
+
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,8 @@
static int rr_quick(READ_RECORD *info);
static int rr_sequential(READ_RECORD *info);
static int rr_from_tempfile(READ_RECORD *info);
+static int rr_unpack_from_tempfile(READ_RECORD *info);
+static int rr_unpack_from_buffer(READ_RECORD *info);
static int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(READ_RECORD *info);
@@ -41,8 +44,16 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
info->table=table;
info->file= table->file;
info->forms= &info->table; /* Only one table */
- info->record=table->record[0];
- info->ref_length=table->file->ref_length;
+ if (table->sort.addon_field)
+ {
+ info->rec_buf= table->sort.addon_buf;
+ info->ref_length= table->sort.addon_length;
+ }
+ else
+ {
+ info->record= table->record[0];
+ info->ref_length= table->file->ref_length;
+ }
info->select=select;
info->print_error=print_error;
info->ignore_not_found_rows= 0;
@@ -51,11 +62,12 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (select && my_b_inited(&select->file))
tempfile= &select->file;
else
- tempfile= table->io_cache;
+ tempfile= table->sort.io_cache;
if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
{
DBUG_PRINT("info",("using rr_from_tempfile"));
- info->read_record=rr_from_tempfile;
+ info->read_record= (table->sort.addon_field ?
+ rr_unpack_from_tempfile : rr_from_tempfile);
info->io_cache=tempfile;
reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
info->ref_pos=table->file->ref;
@@ -85,13 +97,15 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
DBUG_PRINT("info",("using rr_quick"));
info->read_record=rr_quick;
}
- else if (table->record_pointers)
+ else if (table->sort.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;
- info->read_record= rr_from_pointers;
+ info->cache_pos=table->sort.record_pointers;
+ info->cache_end=info->cache_pos+
+ table->sort.found_records*info->ref_length;
+ info->read_record= (table->sort.addon_field ?
+ rr_unpack_from_buffer : rr_from_pointers);
}
else
{
@@ -112,7 +126,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
void end_read_record(READ_RECORD *info)
-{ /* free cache if used */
+{ /* free cache if used */
if (info->cache)
{
my_free_lock((char*) info->cache,MYF(0));
@@ -120,6 +134,7 @@ void end_read_record(READ_RECORD *info)
}
if (info->table)
{
+ filesort_free_buffers(info->table);
(void) info->file->extra(HA_EXTRA_NO_CACHE);
(void) info->file->rnd_end();
info->table=0;
@@ -200,6 +215,34 @@ tryNext:
} /* rr_from_tempfile */
+/*
+ Read a result set record from a temporary file after sorting
+
+ SYNOPSIS
+ rr_unpack_from_tempfile()
+ info Reference to the context including record descriptors
+
+ DESCRIPTION
+ The function first reads the next sorted record from the temporary file.
+ into a buffer. If a success it calls a callback function that unpacks
+ the fields values use in the result set from this buffer into their
+ positions in the regular record buffer.
+
+ RETURN
+ 0 - Record successfully read.
+ -1 - There is no record to be read anymore.
+*/
+
+static int rr_unpack_from_tempfile(READ_RECORD *info)
+{
+ if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
+ return -1;
+ TABLE *table= info->table;
+ (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
+
+ return 0;
+}
+
static int rr_from_pointers(READ_RECORD *info)
{
int tmp;
@@ -228,6 +271,34 @@ tryNext:
return tmp;
}
+/*
+ Read a result set record from a buffer after sorting
+
+ SYNOPSIS
+ rr_unpack_from_buffer()
+ info Reference to the context including record descriptors
+
+ DESCRIPTION
+ The function first reads the next sorted record from the sort buffer.
+ If a success it calls a callback function that unpacks
+ the fields values use in the result set from this buffer into their
+ positions in the regular record buffer.
+
+ RETURN
+ 0 - Record successfully read.
+ -1 - There is no record to be read anymore.
+*/
+
+static int rr_unpack_from_buffer(READ_RECORD *info)
+{
+ if (info->cache_pos == info->cache_end)
+ return -1; /* End of buffer */
+ TABLE *table= info->table;
+ (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
+ info->cache_pos+= info->ref_length;
+
+ return 0;
+}
/* cacheing of records from a database */
static int init_rr_cache(READ_RECORD *info)
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 46791c13219..58769827bed 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -873,7 +873,6 @@ int load_master_data(THD* thd)
// don't hit the magic number
if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
- active_mi->rli.pending = 0;
flush_master_info(active_mi);
}
mc_mysql_free_result(master_status_res);
@@ -897,9 +896,13 @@ int load_master_data(THD* thd)
return 1;
}
pthread_mutex_lock(&active_mi->rli.data_lock);
- active_mi->rli.master_log_pos = active_mi->master_log_pos;
- strmake(active_mi->rli.master_log_name,active_mi->master_log_name,
- sizeof(active_mi->rli.master_log_name)-1);
+ active_mi->rli.group_master_log_pos = active_mi->master_log_pos;
+ strmake(active_mi->rli.group_master_log_name,active_mi->master_log_name,
+ sizeof(active_mi->rli.group_master_log_name)-1);
+ /*
+ No need to update rli.event* coordinates, they will be when the slave
+ threads start ; only rli.group* coordinates are necessary here.
+ */
flush_relay_log_info(&active_mi->rli);
pthread_cond_broadcast(&active_mi->rli.data_cond);
pthread_mutex_unlock(&active_mi->rli.data_lock);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index d39a506c82d..e4adbb0a318 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -167,6 +167,8 @@ sys_var_thd_ulong sys_pseudo_thread_id("pseudo_thread_id",
sys_var_thd_ha_rows sys_max_join_size("max_join_size",
&SV::max_join_size,
fix_max_join_size);
+sys_var_thd_ulong sys_max_length_for_sort_data("max_length_for_sort_data",
+ &SV::max_length_for_sort_data);
#ifndef TO_BE_DELETED /* Alias for max_join_size */
sys_var_thd_ha_rows sys_sql_max_join_size("sql_max_join_size",
&SV::max_join_size,
@@ -201,6 +203,10 @@ sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
&SV::read_buff_size);
sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
&SV::read_rnd_buff_size);
+#ifdef HAVE_REPLICATION
+sys_var_bool_ptr sys_relay_log_purge("relay_log_purge",
+ &relay_log_purge);
+#endif
sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank",
&rpl_recovery_rank);
sys_var_long_ptr sys_query_cache_size("query_cache_size",
@@ -381,6 +387,7 @@ sys_var *sys_variables[]=
&sys_max_error_count,
&sys_max_heap_table_size,
&sys_max_join_size,
+ &sys_max_length_for_sort_data,
&sys_max_prep_stmt_count,
&sys_max_sort_length,
&sys_max_tmp_tables,
@@ -407,6 +414,9 @@ sys_var *sys_variables[]=
&sys_rand_seed2,
&sys_read_buff_size,
&sys_read_rnd_buff_size,
+#ifdef HAVE_REPLICATION
+ &sys_relay_log_purge,
+#endif
&sys_rpl_recovery_rank,
&sys_safe_updates,
&sys_select_limit,
@@ -534,6 +544,9 @@ struct show_var_st init_vars[]= {
{sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS},
{sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS},
{sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS},
+ {sys_max_length_for_sort_data.name,
+ (char*) &sys_max_length_for_sort_data,
+ SHOW_SYS},
{sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS},
{sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS},
{sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS},
@@ -563,6 +576,9 @@ struct show_var_st init_vars[]= {
{sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
{sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
{sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
+#ifdef HAVE_REPLICATION
+ {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
+#endif
{sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
#ifdef HAVE_QUERY_CACHE
{sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS},
diff --git a/sql/slave.cc b/sql/slave.cc
index fa7ab180eaa..eae795ae760 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -217,11 +217,7 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
- If not, open the 'log' binary file.
TODO
- - check proper initialization of master_log_name/master_log_pos
- - We may always want to delete all logs before 'log'.
- Currently if we are not calling this with 'log' as NULL or the first
- log we will never delete relay logs.
- If we want this we should not set skip_log_purge to 1.
+ - check proper initialization of group_master_log_name/group_master_log_pos
RETURN VALUES
0 ok
@@ -248,7 +244,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
rli->cur_log_fd = -1;
}
- rli->relay_log_pos = pos;
+ rli->group_relay_log_pos = rli->event_relay_log_pos = pos;
/*
Test to see if the previous run was with the skip of purging
@@ -260,18 +256,15 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
goto err;
}
- if (log) // If not first log
+ if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1))
{
- if (strcmp(log, rli->linfo.log_file_name))
- rli->skip_log_purge= 1; // Different name; Don't purge
- if (rli->relay_log.find_log_pos(&rli->linfo, log, 1))
- {
- *errmsg="Could not find target log during relay log initialization";
- goto err;
- }
+ *errmsg="Could not find target log during relay log initialization";
+ goto err;
}
- strmake(rli->relay_log_name,rli->linfo.log_file_name,
- sizeof(rli->relay_log_name)-1);
+ strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->group_relay_log_name)-1);
+ strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->event_relay_log_name)-1);
if (rli->relay_log.is_active(rli->linfo.log_file_name))
{
/*
@@ -302,7 +295,7 @@ err:
If we don't purge, we can't honour relay_log_space_limit ;
silently discard it
*/
- if (rli->skip_log_purge)
+ if (!relay_log_purge)
rli->log_space_limit= 0;
pthread_cond_broadcast(&rli->data_cond);
if (need_data_lock)
@@ -383,9 +376,8 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
to display fine in any case.
*/
- rli->master_log_name[0]= 0;
- rli->master_log_pos= 0;
- rli->pending= 0;
+ rli->group_master_log_name[0]= 0;
+ rli->group_master_log_pos= 0;
if (!rli->inited)
DBUG_RETURN(0);
@@ -402,16 +394,18 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
goto err;
}
/* Save name of used relay log file */
- strmake(rli->relay_log_name, rli->relay_log.get_log_fname(),
- sizeof(rli->relay_log_name)-1);
+ strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
+ sizeof(rli->group_relay_log_name)-1);
+ strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
+ sizeof(rli->event_relay_log_name)-1);
// Just first log with magic number and nothing else
rli->log_space_total= BIN_LOG_HEADER_SIZE;
- rli->relay_log_pos= BIN_LOG_HEADER_SIZE;
+ rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
rli->relay_log.reset_bytes_written();
if (!just_reset)
- error= init_relay_log_pos(rli, rli->relay_log_name, rli->relay_log_pos,
- 0 /* do not need data lock */, errmsg);
-
+ error= init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos,
+ 0 /* do not need data lock */, errmsg);
+
err:
#ifndef DBUG_OFF
char buf[22];
@@ -1238,13 +1232,11 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
pthread_mutex_lock(&rli->data_lock);
info_fd = rli->info_fd;
- rli->pending = 0;
rli->cur_log_fd = -1;
rli->slave_skip_counter=0;
rli->abort_pos_wait=0;
- rli->skip_log_purge=0;
- rli->log_space_limit = relay_log_space_limit;
- rli->log_space_total = 0;
+ rli->log_space_limit= relay_log_space_limit;
+ rli->log_space_total= 0;
// TODO: make this work with multi-master
if (!opt_relay_logname)
@@ -1285,8 +1277,8 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
&msg))
goto err;
- rli->master_log_name[0]= 0;
- rli->master_log_pos= 0;
+ rli->group_master_log_name[0]= 0;
+ rli->group_master_log_pos= 0;
rli->info_fd= info_fd;
}
else // file exists
@@ -1307,31 +1299,33 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
rli->info_fd = info_fd;
int relay_log_pos, master_log_pos;
- if (init_strvar_from_file(rli->relay_log_name,
- sizeof(rli->relay_log_name), &rli->info_file,
+ if (init_strvar_from_file(rli->group_relay_log_name,
+ sizeof(rli->group_relay_log_name), &rli->info_file,
"") ||
init_intvar_from_file(&relay_log_pos,
&rli->info_file, BIN_LOG_HEADER_SIZE) ||
- init_strvar_from_file(rli->master_log_name,
- sizeof(rli->master_log_name), &rli->info_file,
+ init_strvar_from_file(rli->group_master_log_name,
+ sizeof(rli->group_master_log_name), &rli->info_file,
"") ||
init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
{
msg="Error reading slave log configuration";
goto err;
}
- rli->relay_log_pos= relay_log_pos;
- rli->master_log_pos= master_log_pos;
+ strmake(rli->event_relay_log_name,rli->group_relay_log_name,
+ sizeof(rli->event_relay_log_name)-1);
+ rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
+ rli->group_master_log_pos= master_log_pos;
if (init_relay_log_pos(rli,
- rli->relay_log_name,
- rli->relay_log_pos,
+ rli->group_relay_log_name,
+ rli->group_relay_log_pos,
0 /* no data lock*/,
&msg))
goto err;
}
- DBUG_ASSERT(rli->relay_log_pos >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos);
+ DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
/*
Now change the cache from READ to WRITE - must do this
before flush_relay_log_info
@@ -1407,7 +1401,7 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli)
{
LOG_INFO linfo;
DBUG_ENTER("count_relay_log_space");
- rli->log_space_total = 0;
+ rli->log_space_total= 0;
if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
{
sql_print_error("Could not find first log while counting relay log space");
@@ -1631,10 +1625,10 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store((uint32) mi->connect_retry);
protocol->store(mi->master_log_name, &my_charset_bin);
protocol->store((ulonglong) mi->master_log_pos);
- protocol->store(mi->rli.relay_log_name +
- dirname_length(mi->rli.relay_log_name), &my_charset_bin);
- protocol->store((ulonglong) mi->rli.relay_log_pos);
- protocol->store(mi->rli.master_log_name, &my_charset_bin);
+ protocol->store(mi->rli.group_relay_log_name +
+ dirname_length(mi->rli.group_relay_log_name), &my_charset_bin);
+ protocol->store((ulonglong) mi->rli.group_relay_log_pos);
+ protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(&replicate_do_db);
@@ -1642,7 +1636,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store((uint32) mi->rli.last_slave_errno);
protocol->store(mi->rli.last_slave_error, &my_charset_bin);
protocol->store((uint32) mi->rli.slave_skip_counter);
- protocol->store((ulonglong) mi->rli.master_log_pos);
+ protocol->store((ulonglong) mi->rli.group_master_log_pos);
protocol->store((ulonglong) mi->rli.log_space_total);
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
@@ -1673,17 +1667,15 @@ bool flush_master_info(MASTER_INFO* mi)
st_relay_log_info::st_relay_log_info()
- :info_fd(-1), cur_log_fd(-1), master_log_pos(0), save_temporary_tables(0),
- cur_log_old_open_count(0), log_space_total(0), ignore_log_space_limit(0),
- slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0),
- sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
- slave_running(0), skip_log_purge(0),
- inside_transaction(0) /* the default is autocommit=1 */
-{
- relay_log_name[0] = master_log_name[0] = 0;
+ :info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
+ cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
+ ignore_log_space_limit(0), slave_skip_counter(0), abort_pos_wait(0),
+ slave_run_id(0), sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
+ slave_running(0)
+{
+ group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0;
last_slave_error[0]=0;
-
bzero(&info_file,sizeof(info_file));
bzero(&cache_buf, sizeof(cache_buf));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
@@ -1745,8 +1737,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
set_timespec(abstime,timeout);
DBUG_ENTER("wait_for_pos");
- DBUG_PRINT("enter",("master_log_name: '%s' pos: %lu timeout: %ld",
- master_log_name, (ulong) master_log_pos,
+ DBUG_PRINT("enter",("group_master_log_name: '%s' pos: %lu timeout: %ld",
+ group_master_log_name, (ulong) group_master_log_pos,
(long) timeout));
pthread_mutex_lock(&data_lock);
@@ -1796,10 +1788,10 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
{
bool pos_reached;
int cmp_result= 0;
- DBUG_ASSERT(*master_log_name || master_log_pos == 0);
- if (*master_log_name)
+ DBUG_ASSERT(*group_master_log_name || group_master_log_pos == 0);
+ if (*group_master_log_name)
{
- char *basename= master_log_name + dirname_length(master_log_name);
+ char *basename= group_master_log_name + dirname_length(group_master_log_name);
/*
First compare the parts before the extension.
Find the dot in the master's log basename,
@@ -1814,13 +1806,13 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
}
// Now compare extensions.
char *q_end;
- ulong master_log_name_extension= strtoul(q, &q_end, 10);
- if (master_log_name_extension < log_name_extension)
+ ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
+ if (group_master_log_name_extension < log_name_extension)
cmp_result = -1 ;
else
- cmp_result= (master_log_name_extension > log_name_extension) ? 1 : 0 ;
+ cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
}
- pos_reached = ((!cmp_result && master_log_pos >= (ulonglong)log_pos) ||
+ pos_reached = ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
cmp_result > 0);
if (pos_reached || thd->killed)
break;
@@ -2127,7 +2119,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
(rli->slave_skip_counter && type_code != ROTATE_EVENT))
{
/* TODO: I/O thread should not even log events with the same server id */
- rli->inc_pos(ev->get_event_len(),
+ rli->inc_group_relay_log_pos(ev->get_event_len(),
type_code != STOP_EVENT ? ev->log_pos : LL(0),
1/* skip lock*/);
flush_relay_log_info(rli);
@@ -2497,15 +2489,13 @@ slave_begin:
rli->abort_slave = 0;
pthread_mutex_unlock(&rli->run_lock);
pthread_cond_broadcast(&rli->start_cond);
- // This should always be set to 0 when the slave thread is started
- rli->pending = 0;
//tell the I/O thread to take relay_log_space_limit into account from now on
rli->ignore_log_space_limit= 0;
if (init_relay_log_pos(rli,
- rli->relay_log_name,
- rli->relay_log_pos,
+ rli->group_relay_log_name,
+ rli->group_relay_log_pos,
1 /*need data lock*/, &errmsg))
{
sql_print_error("Error initializing relay log position: %s",
@@ -2513,18 +2503,18 @@ slave_begin:
goto err;
}
THD_CHECK_SENTRY(thd);
- DBUG_ASSERT(rli->relay_log_pos >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos);
+ DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
DBUG_ASSERT(rli->sql_thd == thd);
DBUG_PRINT("master_info",("log_file_name: %s position: %s",
- rli->master_log_name,
- llstr(rli->master_log_pos,llbuff)));
+ rli->group_master_log_name,
+ llstr(rli->group_master_log_pos,llbuff)));
if (global_system_variables.log_warnings)
sql_print_error("Slave SQL thread initialized, starting replication in \
log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
- llstr(rli->master_log_pos,llbuff),rli->relay_log_name,
- llstr(rli->relay_log_pos,llbuff1));
+ llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
+ llstr(rli->group_relay_log_pos,llbuff1));
/* Read queries from the IO/THREAD until this thread is killed */
@@ -2541,7 +2531,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
Error running query, slave SQL thread aborted. Fix the problem, and restart \
the slave SQL thread with \"SLAVE START\". We stopped at log \
'%s' position %s",
- RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
+ RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
goto err;
}
}
@@ -2549,7 +2539,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
/* Thread stopped. Print the current replication position to the log */
sql_print_error("Slave SQL thread exiting, replication stopped in log \
'%s' at position %s",
- RPL_LOG_NAME, llstr(rli->master_log_pos,llbuff));
+ RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
err:
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -2699,7 +2689,7 @@ err:
rev The rotate log event read from the binary log
DESCRIPTION
- Updates the master info and relay data with the place in the next binary
+ Updates the master info with the place in the next binary
log where we should start reading.
NOTES
@@ -3073,18 +3063,14 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
IO_CACHE *file = &rli->info_file;
char buff[FN_REFLEN*2+22*2+4], *pos;
- /* sql_thd is not set when calling from init_slave() */
- if ((rli->sql_thd && rli->sql_thd->options & OPTION_BEGIN))
- return 0; // Wait for COMMIT
-
my_b_seek(file, 0L);
- pos=strmov(buff, rli->relay_log_name);
+ pos=strmov(buff, rli->group_relay_log_name);
*pos++='\n';
- pos=longlong2str(rli->relay_log_pos, pos, 10);
+ pos=longlong2str(rli->group_relay_log_pos, pos, 10);
*pos++='\n';
- pos=strmov(pos, rli->master_log_name);
+ pos=strmov(pos, rli->group_master_log_name);
*pos++='\n';
- pos=longlong2str(rli->master_log_pos, pos, 10);
+ pos=longlong2str(rli->group_master_log_pos, pos, 10);
*pos='\n';
if (my_b_write(file, (byte*) buff, (ulong) (pos-buff)+1))
error=1;
@@ -3107,7 +3093,7 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
DBUG_ENTER("reopen_relay_log");
IO_CACHE *cur_log = rli->cur_log=&rli->cache_buf;
- if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name,
+ if ((rli->cur_log_fd=open_binlog(cur_log,rli->event_relay_log_name,
errmsg)) <0)
DBUG_RETURN(0);
/*
@@ -3115,7 +3101,7 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
relay_log_pos Current log pos
pending Number of bytes already processed from the event
*/
- my_b_seek(cur_log,rli->relay_log_pos + rli->pending);
+ my_b_seek(cur_log,rli->event_relay_log_pos);
DBUG_RETURN(cur_log);
}
@@ -3124,7 +3110,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
{
Log_event* ev;
IO_CACHE* cur_log = rli->cur_log;
- pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
+ pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
const char* errmsg=0;
THD* thd = rli->sql_thd;
DBUG_ENTER("next_event");
@@ -3173,7 +3159,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
}
}
DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(cur_log) == rli->relay_log_pos + rli->pending);
+ DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
/*
Relay log is always in new format - if the master is 3.23, the
I/O thread will convert the format for us
@@ -3240,8 +3226,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
// prevent the I/O thread from blocking next times
rli->ignore_log_space_limit= 1;
// If the I/O thread is blocked, unblock it
- pthread_cond_broadcast(&rli->log_space_cond);
pthread_mutex_unlock(&rli->log_space_lock);
+ pthread_cond_broadcast(&rli->log_space_cond);
// Note that wait_for_update unlocks lock_log !
rli->relay_log.wait_for_update(rli->sql_thd);
// re-acquire data lock since we released it earlier
@@ -3258,16 +3244,25 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
my_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
- /*
- TODO: make skip_log_purge a start-up option. At this point this
- is not critical priority
- */
- if (!rli->skip_log_purge)
+ if (relay_log_purge)
{
- // purge_first_log will properly set up relay log coordinates in rli
- if (rli->relay_log.purge_first_log(rli))
+ /*
+ purge_first_log will properly set up relay log coordinates in rli.
+ If the group's coordinates are equal to the event's coordinates
+ (i.e. the relay log was not rotated in the middle of a group),
+ we can purge this relay log too.
+ We do ulonglong and string comparisons, this may be slow but
+ - purging the last relay log is nice (it can save 1GB of disk), so we
+ like to detect the case where we can do it, and given this,
+ - I see no better detection method
+ - purge_first_log is not called that often
+ */
+ if (rli->relay_log.purge_first_log
+ (rli,
+ rli->group_relay_log_pos == rli->event_relay_log_pos
+ && !strcmp(rli->group_relay_log_name,rli->event_relay_log_name)))
{
- errmsg = "Error purging processed log";
+ errmsg = "Error purging processed logs";
goto err;
}
}
@@ -3285,10 +3280,9 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
errmsg = "error switching to the next log";
goto err;
}
- rli->relay_log_pos = BIN_LOG_HEADER_SIZE;
- rli->pending=0;
- strmake(rli->relay_log_name,rli->linfo.log_file_name,
- sizeof(rli->relay_log_name)-1);
+ rli->event_relay_log_pos = BIN_LOG_HEADER_SIZE;
+ strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->event_relay_log_name)-1);
flush_relay_log_info(rli);
}
@@ -3336,7 +3330,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
event(errno: %d cur_log->error: %d)",
my_errno,cur_log->error);
// set read position to the beginning of the event
- my_b_seek(cur_log,rli->relay_log_pos+rli->pending);
+ my_b_seek(cur_log,rli->event_relay_log_pos);
/* otherwise, we have had a partial read */
errmsg = "Aborting slave SQL thread because of partial event read";
break; // To end of function
diff --git a/sql/slave.h b/sql/slave.h
index a4db7388be5..16ba7f80471 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -92,12 +92,6 @@ typedef struct st_relay_log_info
cur_log_fd - file descriptor of the current read relay log
*/
File info_fd,cur_log_fd;
- /* name of current read relay log */
- char relay_log_name[FN_REFLEN];
- /* master log name corresponding to current read position */
- char master_log_name[FN_REFLEN];
- /* original log position of last processed event */
- volatile my_off_t master_log_pos;
/*
Protected with internal locks.
@@ -142,20 +136,36 @@ typedef struct st_relay_log_info
uint32 cur_log_old_open_count;
/*
- relay_log_pos - Current offset in the relay log.
- pending - In some cases we do not increment offset immediately
- after processing an event, because the following event
- needs to be processed atomically together with this one
- such as:
-
- Intvar_event - sets auto_increment value
- Rand_event - sets the random seed
-
- However, once both events have been processed, we need to
- increment by the cumulative offset. 'pending' stores the
- extra offset to be added to the position.
+ Let's call a group (of events) :
+ - a transaction
+ or
+ - an autocommiting query + its associated events (INSERT_ID,
+ TIMESTAMP...)
+ We need these rli coordinates :
+ - relay log name and position of the beginning of the group we currently are
+ executing. Needed to know where we have to restart when replication has
+ stopped in the middle of a group (which has been rolled back by the slave).
+ - relay log name and position just after the event we have just
+ executed. This event is part of the current group.
+ Formerly we only had the immediately above coordinates, plus a 'pending'
+ variable, but this dealt wrong with the case of a transaction starting on a
+ relay log and finishing (commiting) on another relay log. Case which can
+ happen when, for example, the relay log gets rotated because of
+ max_binlog_size.
+ */
+ char group_relay_log_name[FN_REFLEN];
+ ulonglong group_relay_log_pos;
+ char event_relay_log_name[FN_REFLEN];
+ ulonglong event_relay_log_pos;
+ /*
+ Original log name and position of the group we're currently executing
+ (whose coordinates are group_relay_log_name/pos in the relay log)
+ in the master's binlog. These concern the *group*, because in the master's
+ binlog the log_pos that comes with each event is the position of the
+ beginning of the group.
*/
- ulonglong relay_log_pos, pending;
+ char group_master_log_name[FN_REFLEN];
+ volatile my_off_t group_master_log_pos;
/*
Handling of the relay_log_space_limit optional constraint.
@@ -193,38 +203,39 @@ typedef struct st_relay_log_info
/* if not set, the value of other members of the structure are undefined */
bool inited;
volatile bool abort_slave, slave_running;
- bool skip_log_purge;
- bool inside_transaction;
st_relay_log_info();
~st_relay_log_info();
- inline void inc_pending(ulonglong val)
+
+ inline void inc_event_relay_log_pos(ulonglong val)
{
- pending += val;
+ event_relay_log_pos+= val;
}
- /* TODO: this probably needs to be fixed */
- inline void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
+
+ void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
{
if (!skip_lock)
pthread_mutex_lock(&data_lock);
- relay_log_pos += val+pending;
- pending = 0;
- if (log_pos)
- master_log_pos = log_pos+ val;
+ inc_event_relay_log_pos(val);
+ group_relay_log_pos= event_relay_log_pos;
+ strmake(group_relay_log_name,event_relay_log_name,
+ sizeof(group_relay_log_name)-1);
+ /*
+ If the slave does not support transactions and replicates a transaction,
+ users should not trust group_master_log_pos (which they can display with
+ SHOW SLAVE STATUS or read from relay-log.info), because to compute
+ group_master_log_pos the slave relies on log_pos stored in the master's
+ binlog, but if we are in a master's transaction these positions are always
+ the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does
+ not advance as it should on the non-transactional slave (it advances by
+ big leaps, whereas it should advance by small leaps).
+ */
+ if (log_pos) // 3.23 binlogs don't have log_posx
+ group_master_log_pos= log_pos+ val;
pthread_cond_broadcast(&data_cond);
if (!skip_lock)
pthread_mutex_unlock(&data_lock);
}
- /*
- thread safe read of position - not needed if we are in the slave thread,
- but required otherwise as var is a longlong
- */
- inline void read_pos(ulonglong& var)
- {
- pthread_mutex_lock(&data_lock);
- var = relay_log_pos;
- pthread_mutex_unlock(&data_lock);
- }
int wait_for_pos(THD* thd, String* log_name, longlong log_pos,
longlong timeout);
@@ -334,7 +345,7 @@ typedef struct st_table_rule_ent
#define TABLE_RULE_ARR_SIZE 16
#define MAX_SLAVE_ERRMSG 1024
-#define RPL_LOG_NAME (rli->master_log_name[0] ? rli->master_log_name :\
+#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
"FIRST")
#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
"FIRST")
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 4bed99489de..5ac52032a5f 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1281,7 +1281,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
DBUG_RETURN(1); /* purecov: deadcode */
}
- store_record(table,1);
+ store_record(table,record[1]);
table->field[2]->store(new_password,(uint) strlen(new_password), &my_charset_latin1);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
@@ -1372,7 +1372,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
goto end;
}
old_row_exists = 0;
- restore_record(table,2); // cp empty row from record[2]
+ restore_record(table,default_values); // cp empty row from default_values
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
@@ -1380,7 +1380,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
else
{
old_row_exists = 1;
- store_record(table,1); // Save copy for update
+ store_record(table,record[1]); // Save copy for update
if (combo.password.str) // If password given
table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
}
@@ -1455,7 +1455,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
We should NEVER delete from the user table, as a uses can still
use mysqld even if he doesn't have any privileges in the user table!
*/
- if (cmp_record(table,1) &&
+ if (cmp_record(table,record[1]) &&
(error=table->file->update_row(table->record[1],table->record[0])))
{ // This should never happen
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1539,7 +1539,7 @@ static int replace_db_table(TABLE *table, const char *db,
goto abort;
}
old_row_exists = 0;
- restore_record(table,2); // cp empty row from record[2]
+ restore_record(table,default_values); // cp empty row from default_values
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
@@ -1547,7 +1547,7 @@ static int replace_db_table(TABLE *table, const char *db,
else
{
old_row_exists = 1;
- store_record(table,1);
+ store_record(table,record[1]);
}
store_rights=get_rights_for_db(rights);
@@ -1827,7 +1827,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
continue; /* purecov: inspected */
}
old_row_exists = 0;
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
key_restore(table,key,0,key_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(), &my_charset_latin1);
}
@@ -1841,7 +1841,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
else
privileges |= tmp;
old_row_exists = 1;
- store_record(table,1); // copy original row
+ store_record(table,record[1]); // copy original row
}
table->field[6]->store((longlong) get_rights_for_column(privileges));
@@ -1895,7 +1895,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
ulong privileges = (ulong) table->field[6]->val_int();
privileges=fix_rights_for_column(privileges);
- store_record(table,1);
+ store_record(table,record[1]);
if (privileges & rights) // is in this record the priv to be revoked ??
{
@@ -1970,12 +1970,12 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
DBUG_RETURN(-1); /* purecov: deadcode */
}
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
- store_record(table,1); // store at pos 1
+ store_record(table,record[1]); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,0,
@@ -1995,7 +1995,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
DBUG_RETURN(-1); /* purecov: deadcode */
}
old_row_exists = 0;
- restore_record(table,1); // Get saved record
+ restore_record(table,record[1]); // Get saved record
}
store_table_rights= get_rights_for_table(rights);
@@ -2003,7 +2003,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
if (old_row_exists)
{
ulong j,k;
- store_record(table,1);
+ store_record(table,record[1]);
j = (ulong) table->field[6]->val_int();
k = (ulong) table->field[7]->val_int();
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d92b2ba16ff..e374cdb3696 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -245,16 +245,11 @@ static void free_cache_entry(TABLE *table)
void free_io_cache(TABLE *table)
{
DBUG_ENTER("free_io_cache");
- if (table->io_cache)
+ if (table->sort.io_cache)
{
- close_cached_file(table->io_cache);
- my_free((gptr) table->io_cache,MYF(0));
- table->io_cache=0;
- }
- if (table->record_pointers)
- {
- my_free((gptr) table->record_pointers,MYF(0));
- table->record_pointers=0;
+ close_cached_file(table->sort.io_cache);
+ my_free((gptr) table->sort.io_cache,MYF(0));
+ table->sort.io_cache=0;
}
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d3cb843ad85..925afde2202 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -145,10 +145,12 @@ public:
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
- int update_log_index(LOG_INFO* linfo);
- int purge_logs(THD* thd, const char* to_log);
- int purge_logs_before_date(THD* thd, time_t purge_time);
- int purge_first_log(struct st_relay_log_info* rli);
+ int update_log_index(LOG_INFO* linfo, bool need_update_threads);
+ int purge_logs(const char *to_log, bool included,
+ bool need_mutex, bool need_update_threads,
+ ulonglong *decrease_log_space);
+ int purge_logs_before_date(time_t purge_time);
+ int purge_first_log(struct st_relay_log_info* rli, bool included);
bool reset_logs(THD* thd);
// if we are exiting, we also want to close the index file
void close(bool exiting = 0);
@@ -352,6 +354,7 @@ struct system_variables
ulong max_allowed_packet;
ulong max_error_count;
ulong max_heap_table_size;
+ ulong max_length_for_sort_data;
ulong max_prep_stmt_count;
ulong max_sort_length;
ulong max_tmp_tables;
@@ -815,11 +818,52 @@ public:
void abort();
};
+#include <myisam.h>
+
+/* Param to create temporary tables when doing SELECT:s */
+
+class TMP_TABLE_PARAM :public Sql_alloc
+{
+ public:
+ List<Item> copy_funcs;
+ List<Item> save_copy_funcs;
+ List_iterator_fast<Item> copy_funcs_it;
+ Copy_field *copy_field, *copy_field_end;
+ Copy_field *save_copy_field, *save_copy_field_end;
+ byte *group_buff;
+ Item **items_to_copy; /* Fields in tmp table */
+ MI_COLUMNDEF *recinfo,*start_recinfo;
+ KEY *keyinfo;
+ ha_rows end_write_records;
+ uint field_count,sum_func_count,func_count;
+ uint hidden_field_count;
+ 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), group_null_parts(0)
+ {}
+ ~TMP_TABLE_PARAM()
+ {
+ cleanup();
+ }
+ inline void cleanup(void)
+ {
+ if (copy_field) /* Fix for Intel compiler */
+ {
+ delete [] copy_field;
+ copy_field=0;
+ }
+ }
+};
+
class select_union :public select_result {
public:
TABLE *table;
COPY_INFO info;
- TMP_TABLE_PARAM *tmp_table_param;
+ TMP_TABLE_PARAM tmp_table_param;
bool not_describe;
select_union(TABLE *table_par);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 05f84616a4c..6bb336a87a6 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -124,14 +124,17 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
bzero((char*) &tables,sizeof(tables));
tables.table = table;
- table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (setup_order(thd, 0, &tables, fields, all_fields, order) ||
- !(sortorder=make_unireg_sortorder(order, &length)) ||
- (table->found_records = filesort(thd, table, sortorder, length,
- (SQL_SELECT *) 0, HA_POS_ERROR,
- &examined_rows))
- == HA_POS_ERROR)
+ if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
+ all_fields.elements)||
+ setup_order(thd, thd->lex.select_lex.ref_pointer_array, &tables,
+ fields, all_fields, order) ||
+ !(sortorder=make_unireg_sortorder(order, &length)) ||
+ (table->sort.found_records = filesort(thd, table, sortorder, length,
+ (SQL_SELECT *) 0, HA_POS_ERROR,
+ &examined_rows))
+ == HA_POS_ERROR)
{
delete select;
free_underlaid_joins(thd, &thd->lex.select_lex);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index ca761140955..7f555f37d40 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -151,7 +151,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if ((derived_result=new select_union(table)))
{
- derived_result->tmp_table_param=&tmp_table_param;
+ derived_result->tmp_table_param=tmp_table_param;
unit->offset_limit_cnt= select_cursor->offset_limit;
unit->select_limit_cnt= select_cursor->select_limit+
select_cursor->offset_limit;
@@ -194,7 +194,10 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
{
// to fix a problem in EXPLAIN
if (tables)
- tables->table_list->table=tables->table;
+ {
+ for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
+ cursor->table_list->table=cursor->table;
+ }
}
else
unit->exclude_level();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index dcb39f8526f..7418140517c 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -184,6 +184,15 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->proc_info="init";
thd->used_tables=0;
values= its++;
+
+ if (duplic == DUP_UPDATE && !table->insert_values)
+ {
+ /* it should be allocated before Item::fix_fields() */
+ table->insert_values=alloc_root(&table->mem_root, table->rec_buff_length);
+ if (!table->insert_values)
+ goto abort;
+ }
+
if (check_insert_fields(thd,table,fields,*values,1) ||
setup_tables(insert_table_list) ||
setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
@@ -248,7 +257,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
{
if (fields.elements || !value_count)
{
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
if (fill_record(fields,*values)|| thd->net.report_error ||
check_null_fields(thd,table))
{
@@ -264,9 +273,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
else
{
if (thd->used_tables) // Column used in values()
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
else
- table->record[0][0]=table->record[2][0]; // Fix delete marker
+ table->record[0][0]=table->default_values[0]; // Fix delete marker
if (fill_record(table->field,*values) || thd->net.report_error)
{
if (values_list.elements != 1 && ! thd->net.report_error)
@@ -333,7 +342,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->insert_id(id); // For update log
else if (table->next_number_field)
id=table->next_number_field->val_int(); // Return auto_increment value
-
+
transactional_table= table->file->has_transactions();
log_delayed= (transactional_table || table->tmp_table);
if ((info.copied || info.deleted) && (error <= 0 || !transactional_table))
@@ -383,7 +392,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
char buff[160];
if (duplic == DUP_IGNORE)
sprintf(buff,ER(ER_INSERT_INFO),info.records,
- (lock_type == TL_WRITE_DELAYED) ? 0 :
+ (lock_type == TL_WRITE_DELAYED) ? 0 :
info.records-info.copied,
thd->cuted_fields);
else
@@ -392,12 +401,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff);
}
free_underlaid_joins(thd, &thd->lex.select_lex);
+ table->insert_values=0;
DBUG_RETURN(0);
abort:
if (lock_type == TL_WRITE_DELAYED)
end_delayed_insert(thd);
free_underlaid_joins(thd, &thd->lex.select_lex);
+ table->insert_values=0;
DBUG_RETURN(-1);
}
@@ -482,7 +493,8 @@ int write_record(TABLE *table,COPY_INFO *info)
that matches, is updated. If update causes a conflict again,
an error is returned
*/
- restore_record(table,1);
+ store_record(table,insert_values);
+ restore_record(table,record[1]);
if (fill_record(*info->update_fields,*info->update_values))
goto err;
if ((error=table->file->update_row(table->record[1],table->record[0])))
@@ -1349,7 +1361,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (check_insert_fields(thd,table,*fields,values,1))
DBUG_RETURN(1);
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
thd->count_cuted_fields=1; // calc cuted fields
thd->cuted_fields=0;
@@ -1480,7 +1492,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
table->next_number_field=table->found_next_number_field;
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
thd->count_cuted_fields=1; // count warnings
thd->cuted_fields=0;
if (info.handle_duplicates == DUP_IGNORE ||
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d88908d9e0f..9bc4dfc74e7 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1402,6 +1402,17 @@ ulong st_select_lex::get_table_join_options()
return table_join_options;
}
+st_select_lex::st_select_lex(struct st_lex *lex)
+{
+ select_number= ++lex->thd->select_number;
+ init_query();
+ init_select();
+ include_neighbour(lex->current_select);
+ include_global((st_select_lex_node**)&lex->all_selects_list);
+ lex->current_select= this;
+}
+
+
/*
There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables in sql_parse.cc
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 75ec2f2d3fb..e03814bcd2f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -404,6 +404,8 @@ public:
}
friend void mysql_init_query(THD *thd);
+ st_select_lex(struct st_lex *lex);
+ st_select_lex() {}
void make_empty_select(st_select_lex *last_select)
{
select_number=INT_MAX;
@@ -486,7 +488,7 @@ typedef struct st_lex
CHARSET_INFO *charset;
char *help_arg;
SQL_LIST *gorder_list;
-
+ st_lex() {}
inline void uncacheable()
{
safe_to_cache_query= 0;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 3c43c3d9e3a..a68eada0025 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -238,7 +238,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
lf_info.log_delayed= log_delayed;
read_info.set_io_cache_arg((void*) &lf_info);
}
- restore_record(table,2);
+ restore_record(table,default_values);
thd->count_cuted_fields=1; /* calc cuted fields */
thd->cuted_fields=0L;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d0a970c98b7..ba8a4af794a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3980,7 +3980,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
long purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
- mysql_bin_log.purge_logs_before_date(thd, purge_time);
+ mysql_bin_log.purge_logs_before_date(purge_time);
}
#endif
mysql_slow_log.new_file(1);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 7e9b6aea7b5..0eb444b85c0 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -292,7 +292,7 @@ int purge_master_logs(THD* thd, const char* to_log)
char search_file_name[FN_REFLEN];
mysql_bin_log.make_log_name(search_file_name, to_log);
- int res = mysql_bin_log.purge_logs(thd, search_file_name);
+ int res = mysql_bin_log.purge_logs(search_file_name, 0, 1, 1, NULL);
return purge_error_message(thd, res);
}
@@ -300,7 +300,7 @@ int purge_master_logs(THD* thd, const char* to_log)
int purge_master_logs_before_date(THD* thd, time_t purge_time)
{
- int res = mysql_bin_log.purge_logs_before_date(thd, purge_time);
+ int res = mysql_bin_log.purge_logs_before_date(purge_time);
return purge_error_message(thd ,res);
}
@@ -776,24 +776,25 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
error=1;
goto err;
}
- //delete relay logs, clear relay log coordinates
+ // delete relay logs, clear relay log coordinates
if ((error= purge_relay_logs(&mi->rli, thd,
1 /* just reset */,
&errmsg)))
goto err;
- //Clear master's log coordinates (only for good display of SHOW SLAVE STATUS)
+ // Clear master's log coordinates (only for good display of SHOW SLAVE STATUS)
mi->master_log_name[0]= 0;
mi->master_log_pos= BIN_LOG_HEADER_SIZE;
- //close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
+ // close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
- //and delete these two files
+ // and delete these two files
fn_format(fname, master_info_file, mysql_data_home, "", 4+32);
if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
{
error=1;
goto err;
}
+ // delete relay_log_info_file
fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
{
@@ -874,7 +875,6 @@ int change_master(THD* thd, MASTER_INFO* mi)
// if we change host or port, we must reset the postion
mi->master_log_name[0] = 0;
mi->master_log_pos= BIN_LOG_HEADER_SIZE;
- mi->rli.pending = 0;
}
if (lex_mi->log_file_name)
@@ -883,7 +883,6 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (lex_mi->pos)
{
mi->master_log_pos= lex_mi->pos;
- mi->rli.pending = 0;
}
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
@@ -901,20 +900,22 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (lex_mi->relay_log_name)
{
need_relay_log_purge= 0;
- strmake(mi->rli.relay_log_name,lex_mi->relay_log_name,
- sizeof(mi->rli.relay_log_name)-1);
+ strmake(mi->rli.group_relay_log_name,lex_mi->relay_log_name,
+ sizeof(mi->rli.group_relay_log_name)-1);
+ strmake(mi->rli.event_relay_log_name,lex_mi->relay_log_name,
+ sizeof(mi->rli.event_relay_log_name)-1);
}
if (lex_mi->relay_log_pos)
{
need_relay_log_purge= 0;
- mi->rli.relay_log_pos=lex_mi->relay_log_pos;
+ mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos= lex_mi->relay_log_pos;
}
flush_master_info(mi);
if (need_relay_log_purge)
{
- mi->rli.skip_log_purge= 0;
+ relay_log_purge= 1;
thd->proc_info="purging old relay logs";
if (purge_relay_logs(&mi->rli, thd,
0 /* not only reset, but also reinit */,
@@ -928,11 +929,11 @@ int change_master(THD* thd, MASTER_INFO* mi)
else
{
const char* msg;
- mi->rli.skip_log_purge= 1;
+ relay_log_purge= 0;
/* Relay log is already initialized */
if (init_relay_log_pos(&mi->rli,
- mi->rli.relay_log_name,
- mi->rli.relay_log_pos,
+ mi->rli.group_relay_log_name,
+ mi->rli.group_relay_log_pos,
0 /*no data lock*/,
&msg))
{
@@ -941,12 +942,12 @@ int change_master(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(1);
}
}
- mi->rli.master_log_pos = mi->master_log_pos;
+ mi->rli.group_master_log_pos = mi->master_log_pos;
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
- strmake(mi->rli.master_log_name,mi->master_log_name,
- sizeof(mi->rli.master_log_name)-1);
- if (!mi->rli.master_log_name[0]) // uninitialized case
- mi->rli.master_log_pos=0;
+ strmake(mi->rli.group_master_log_name,mi->master_log_name,
+ sizeof(mi->rli.group_master_log_name)-1);
+ if (!mi->rli.group_master_log_name[0]) // uninitialized case
+ mi->rli.group_master_log_pos=0;
pthread_mutex_lock(&mi->rli.data_lock);
mi->rli.abort_pos_wait++;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f2dc2b2afd6..f324950e3d5 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -868,12 +868,14 @@ JOIN::reinit()
exec_tmp_table1->file->extra(HA_EXTRA_RESET_STATE);
exec_tmp_table1->file->delete_all_rows();
free_io_cache(exec_tmp_table1);
+ filesort_free_buffers(exec_tmp_table1);
}
if (exec_tmp_table2)
{
exec_tmp_table2->file->extra(HA_EXTRA_RESET_STATE);
exec_tmp_table2->file->delete_all_rows();
free_io_cache(exec_tmp_table2);
+ filesort_free_buffers(exec_tmp_table2);
}
if (items0)
memcpy(ref_pointer_array, items0, ref_pointer_array_size);
@@ -1284,7 +1286,10 @@ JOIN::cleanup(THD *thd)
{
delete tab->select;
delete tab->quick;
+ tab->select=0;
+ tab->quick=0;
x_free(tab->cache.buff);
+ tab->cache.buff= 0;
}
}
tmp_join->tmp_join= 0;
@@ -2316,7 +2321,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
we don't make rec less than 100.
*/
if (keyuse->used_tables &
- (map=(keyuse->used_tables & ~join->const_table_map)))
+ (map=(keyuse->used_tables & ~join->const_table_map &
+ ~OUTER_REF_TABLE_BIT)))
{
uint tablenr;
for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ;
@@ -2628,7 +2634,7 @@ static double
prev_record_reads(JOIN *join,table_map found_ref)
{
double found=1.0;
-
+ found_ref&= ~OUTER_REF_TABLE_BIT;
for (POSITION *pos=join->positions ; found_ref ; pos++)
{
if (pos->table->table->map & found_ref)
@@ -2662,7 +2668,7 @@ get_best_combination(JOIN *join)
join->full_join=0;
- used_tables=0;
+ used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read
for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
{
TABLE *form;
@@ -2933,7 +2939,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_RETURN(1); // Impossible const condition
}
}
- used_tables=(select->const_tables=join->const_table_map) | RAND_TABLE_BIT;
+ used_tables=((select->const_tables=join->const_table_map) |
+ OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);
for (uint i=join->const_tables ; i < join->tables ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
@@ -2943,7 +2950,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
*/
if (i == join->tables-1)
- current_map|= RAND_TABLE_BIT;
+ current_map|= OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
bool use_quick_range=0;
used_tables|=current_map;
@@ -3262,7 +3269,10 @@ join_free(JOIN *join, bool full)
first non const table in join->table
*/
if (join->tables > join->const_tables) // Test for not-const tables
+ {
free_io_cache(join->table[join->const_tables]);
+ filesort_free_buffers(join->table[join->const_tables]);
+ }
if (join->select_lex->dependent && !full)
{
for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
@@ -3286,6 +3296,8 @@ join_free(JOIN *join, bool full)
{
delete tab->select;
delete tab->quick;
+ tab->select=0;
+ tab->quick=0;
x_free(tab->cache.buff);
tab->cache.buff= 0;
if (tab->table)
@@ -3445,7 +3457,8 @@ static void update_depend_map(JOIN *join, ORDER *order)
table_map depend_map;
order->item[0]->update_used_tables();
order->depend_map=depend_map=order->item[0]->used_tables();
- if (!(order->depend_map & RAND_TABLE_BIT)) // Not item_sum() or RAND()
+ // Not item_sum(), RAND() and no reference to table outside of sub select
+ if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)))
{
for (JOIN_TAB **tab=join->map2table;
depend_map ;
@@ -3492,7 +3505,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
}
else
{
- if (order_tables & RAND_TABLE_BIT)
+ if (order_tables & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))
*simple_order=0;
else
{
@@ -4010,7 +4023,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item_sum::AVG_FUNC: /* Place for sum & count */
if (group)
return new Field_string(sizeof(double)+sizeof(longlong),
- maybe_null, item->name,table,&my_charset_bin);
+ 0, item->name,table,&my_charset_bin);
else
return new Field_double(item_sum->max_length,maybe_null,
item->name, table, item_sum->decimals);
@@ -4018,7 +4031,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item_sum::STD_FUNC:
if (group)
return new Field_string(sizeof(double)*2+sizeof(longlong),
- maybe_null, item->name,table,&my_charset_bin);
+ 0, item->name,table,&my_charset_bin);
else
return new Field_double(item_sum->max_length, maybe_null,
item->name,table,item_sum->decimals);
@@ -4371,7 +4384,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
goto err;
table->record[1]= table->record[0]+alloc_length;
- table->record[2]= table->record[1]+alloc_length;
+ table->default_values= table->record[1]+alloc_length;
}
copy_func[0]=0; // End marker
@@ -4445,7 +4458,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
param->copy_field_end=copy;
param->recinfo=recinfo;
- store_record(table,2); // Make empty default record
+ store_record(table,default_values); // Make empty default record
if (thd->variables.tmp_table_size == ~(ulong) 0) // No limit
table->max_rows= ~(ha_rows) 0;
@@ -5048,7 +5061,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
if (!found && on_expr)
{ // OUTER JOIN
- restore_record(join_tab->table,2); // Make empty record
+ restore_record(join_tab->table,default_values); // Make empty record
mark_as_null_row(join_tab->table); // For group by without error
if (!select_cond || select_cond->val_int())
{
@@ -5194,10 +5207,10 @@ join_read_system(JOIN_TAB *tab)
empty_record(table); // Make empty record
return -1;
}
- store_record(table,1);
+ store_record(table,record[1]);
}
else if (!table->status) // Only happens with left join
- restore_record(table,1); // restore old record
+ restore_record(table,record[1]); // restore old record
table->null_row=0;
return table->status ? -1 : 0;
}
@@ -5234,12 +5247,12 @@ join_read_const(JOIN_TAB *tab)
}
return -1;
}
- store_record(table,1);
+ store_record(table,record[1]);
}
else if (!(table->status & ~STATUS_NULL_ROW)) // Only happens with left join
{
table->status=0;
- restore_record(table,1); // restore old record
+ restore_record(table,record[1]); // restore old record
}
table->null_row=0;
return table->status ? -1 : 0;
@@ -5622,11 +5635,11 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
TABLE *table=jt->table;
join->select_options ^= OPTION_FOUND_ROWS;
- if (table->record_pointers ||
- (table->io_cache && my_b_inited(table->io_cache)))
+ if (table->sort.record_pointers ||
+ (table->sort.io_cache && my_b_inited(table->sort.io_cache)))
{
/* Using filesort */
- join->send_records= table->found_records;
+ join->send_records= table->sort.found_records;
}
else
{
@@ -5836,7 +5849,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->tmp_table_param.group_buff,0,
HA_READ_KEY_EXACT))
{ /* Update old record */
- restore_record(table,1);
+ restore_record(table,record[1]);
update_tmptable_sum_func(join->sum_funcs,table);
if ((error=table->file->update_row(table->record[1],
table->record[0])))
@@ -5905,7 +5918,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
table->file->print_error(error,MYF(0)); /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
- restore_record(table,1);
+ restore_record(table,record[1]);
update_tmptable_sum_func(join->sum_funcs,table);
if ((error=table->file->update_row(table->record[1],
table->record[0])))
@@ -6461,8 +6474,8 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
if (!(sortorder=make_unireg_sortorder(order,&length)))
goto err; /* purecov: inspected */
/* It's not fatal if the following alloc fails */
- table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
- MYF(MY_WME | MY_ZEROFILL));
+ table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_WME | MY_ZEROFILL));
table->status=0; // May be wrong if quick_select
// If table has a range, move it to select
@@ -6491,9 +6504,9 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
}
if (table->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
- table->found_records=filesort(thd, table,sortorder, length,
- select, filesort_limit, &examined_rows);
- tab->records=table->found_records; // For SQL_CALC_ROWS
+ table->sort.found_records=filesort(thd, table,sortorder, length,
+ select, filesort_limit, &examined_rows);
+ tab->records=table->sort.found_records; // For SQL_CALC_ROWS
delete select; // filesort did select
tab->select=0;
tab->select_cond=0;
@@ -6505,7 +6518,7 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
- DBUG_RETURN(table->found_records == HA_POS_ERROR);
+ DBUG_RETURN(table->sort.found_records == HA_POS_ERROR);
err:
DBUG_RETURN(-1);
}
@@ -7423,7 +7436,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
DBUG_RETURN(0);
map|=a->item[0]->used_tables();
}
- if (!map || (map & RAND_TABLE_BIT))
+ if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
DBUG_RETURN(0);
for (; !(map & tables->table->map) ; tables=tables->next) ;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index ffc98548db4..7f3669f7478 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -113,45 +113,6 @@ typedef struct st_position { /* Used in find_best */
} POSITION;
-/* Param to create temporary tables when doing SELECT:s */
-
-class TMP_TABLE_PARAM :public Sql_alloc
-{
- public:
- List<Item> copy_funcs;
- List<Item> save_copy_funcs;
- List_iterator_fast<Item> copy_funcs_it;
- Copy_field *copy_field, *copy_field_end;
- Copy_field *save_copy_field, *save_copy_field_end;
- byte *group_buff;
- Item **items_to_copy; /* Fields in tmp table */
- MI_COLUMNDEF *recinfo,*start_recinfo;
- KEY *keyinfo;
- ha_rows end_write_records;
- uint field_count,sum_func_count,func_count;
- uint hidden_field_count;
- 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), group_null_parts(0)
- {}
- ~TMP_TABLE_PARAM()
- {
- cleanup();
- }
- inline void cleanup(void)
- {
- if (copy_field) /* Fix for Intel compiler */
- {
- delete [] copy_field;
- copy_field=0;
- }
- }
-};
-
class JOIN :public Sql_alloc
{
public:
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 8d6eccae87a..2b8982f2484 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -694,7 +694,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
if (protocol->send_records_num(&field_list, (ulonglong)file->records) ||
protocol->send_fields(&field_list,0))
DBUG_RETURN(1);
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
Field **ptr,*field;
String *packet= &thd->packet;
@@ -959,7 +959,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
!wild_case_compare(system_charset_info, field->field_name,wild))
field_list.push_back(new Item_field(field));
}
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
if (thd->protocol->send_fields(&field_list,2))
DBUG_VOID_RETURN;
net_flush(&thd->net);
@@ -1041,7 +1041,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
DBUG_ENTER("store_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
- restore_record(table,2); // Get empty record
+ restore_record(table,default_values); // Get empty record
List<Item> field_list;
char tmp[MAX_FIELD_WIDTH];
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 14463a67a28..9f95ffa4884 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -19,6 +19,30 @@
#define MERGEBUFF 7
#define MERGEBUFF2 15
+/*
+ The structure SORT_ADDON_FIELD describes a fixed layout
+ for field values appended to sorted values in records to be sorted
+ in the sort buffer.
+ Only fixed layout is supported now.
+ Null bit maps for the appended values is placed before the values
+ themselves. Offsets are from the last sorted field, that is from the
+ record referefence, which is still last component of sorted records.
+ It is preserved for backward compatiblility.
+ The structure is used tp store values of the additional fields
+ in the sort buffer. It is used also when these values are read
+ from a temporary file/buffer. As the reading procedures are beyond the
+ scope of the 'filesort' code the values have to be retrieved via
+ the callback function 'unpack_addon_fields'.
+*/
+
+typedef struct st_sort_addon_field { /* Sort addon packed field */
+ Field *field; /* Original field */
+ uint offset; /* Offset from the last sorted field */
+ uint null_offset; /* Offset to to null bit from the last sorted field */
+ uint length; /* Length in the sort buffer */
+ uint8 null_bit; /* Null bit mask for the field */
+} SORT_ADDON_FIELD;
+
typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
my_off_t file_pos; /* Where we are in the sort file */
uchar *base,*key; /* key pointers */
@@ -27,15 +51,18 @@ typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
ulong max_keys; /* Max keys in buffert */
} BUFFPEK;
-
typedef struct st_sort_param {
- uint sort_length; /* Length of sort columns */
- uint keys; /* Max keys / buffert */
+ uint rec_length; /* Length of sorted records */
+ uint sort_length; /* Length of sorted columns */
uint ref_length; /* Length of record ref. */
+ uint addon_length; /* Length of added packed fields */
+ uint res_length; /* Length of records in final sorted file/buffer */
+ uint keys; /* Max keys / buffer */
ha_rows max_rows,examined_rows;
TABLE *sort_form; /* For quicker make_sortkey */
SORT_FIELD *local_sortorder;
SORT_FIELD *end;
+ SORT_ADDON_FIELD *addon_field; /* Descriptors for companion fields */
uchar *unique_buff;
bool not_killable;
char* tmp_buffer;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f4bcd6bd684..9e8cefee223 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -486,6 +486,12 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
blob_columns++;
break;
case FIELD_TYPE_GEOMETRY:
+ if (!(file->table_flags() & HA_HAS_GEOMETRY))
+ {
+ my_printf_error(ER_WRONG_USAGE,ER(ER_WRONG_USAGE),MYF(0),
+ "GEOMETRY FIELD TYPE","not supported by this storage engine ");
+ DBUG_RETURN(-1);
+ }
sql_field->pack_flag=FIELDFLAG_GEOM |
pack_length_to_packflag(sql_field->pack_length -
portable_sizeof_char_ptr);
@@ -1756,7 +1762,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
/* Full alter table */
- restore_record(table,2); // Empty record for DEFAULT
+ restore_record(table,default_values); // Empty record for DEFAULT
List_iterator<Alter_drop> drop_it(drop_list);
List_iterator<create_field> def_it(fields);
List_iterator<Alter_column> alter_it(alter_list);
@@ -2342,8 +2348,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (order)
{
- from->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
- MYF(MY_FAE | MY_ZEROFILL));
+ from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
bzero((char*) &tables,sizeof(tables));
tables.table = from;
tables.alias = tables.real_name= from->real_name;
@@ -2355,9 +2361,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
- (from->found_records = filesort(thd, from, sortorder, length,
- (SQL_SELECT *) 0, HA_POS_ERROR,
- &examined_rows))
+ (from->sort.found_records = filesort(thd, from, sortorder, length,
+ (SQL_SELECT *) 0, HA_POS_ERROR,
+ &examined_rows))
== HA_POS_ERROR)
goto err;
};
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 42f4dddea8d..d191550f396 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -429,7 +429,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
- restore_record(table,2); // Get default values for fields
+ restore_record(table,default_values); // Get default values for fields
table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
table->field[1]->store((longlong) u_d->returns);
table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 88c461bc0f8..fe4ca49da14 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -82,7 +82,7 @@ bool select_union::send_data(List<Item> &values)
if (thd->net.last_errno == ER_RECORD_FILE_FULL)
{
thd->clear_error(); // do not report user about table overflow
- if (create_myisam_from_heap(thd, table, tmp_table_param,
+ if (create_myisam_from_heap(thd, table, &tmp_table_param,
info.last_errno, 0))
return 1;
}
@@ -117,7 +117,6 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
{
SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor;
- TMP_TABLE_PARAM tmp_table_param;
DBUG_ENTER("st_select_lex_unit::prepare");
if (prepared)
@@ -125,9 +124,11 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
prepared= 1;
res= 0;
found_rows_for_union= 0;
+ TMP_TABLE_PARAM tmp_table_param;
result= sel_result;
t_and_f= tables_and_fields_initied;
-
+
+ bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM));
thd->lex.current_select= select_cursor= first_select_in_union();
/* Global option */
if (((void*)(global_parameters)) == ((void*)this))
@@ -167,7 +168,6 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
t_and_f= 1;
}
- bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
(ORDER*) 0, !union_option,
@@ -186,7 +186,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
goto err;
union_result->not_describe=1;
- union_result->tmp_table_param=&tmp_table_param;
+ union_result->tmp_table_param=tmp_table_param;
/*
The following piece of code is placed here solely for the purpose of
@@ -251,11 +251,9 @@ int st_select_lex_unit::exec()
{
int do_print_slow= 0;
SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
- SELECT_LEX *select_cursor=first_select_in_union(), *last_select;
+ SELECT_LEX *select_cursor=first_select_in_union();
DBUG_ENTER("st_select_lex_unit::exec");
- LINT_INIT(last_select);
-
if (executed && !(dependent || uncacheable))
DBUG_RETURN(0);
executed= 1;
@@ -270,7 +268,6 @@ int st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
- last_select=sl;
if (optimized)
res= sl->join->reinit();
else
@@ -336,8 +333,7 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
- SELECT_LEX *fake_select = new SELECT_LEX();
- fake_select->make_empty_select(last_select);
+ SELECT_LEX *fake_select = new SELECT_LEX(&thd->lex);
offset_limit_cnt= (select_cursor->braces ?
global_parameters->offset_limit : 0);
select_limit_cnt= (select_cursor->braces ?
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 3e72f79da62..7c5983a0362 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -30,7 +30,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields);
static bool compare_record(TABLE *table, ulong query_id)
{
if (!table->blob_fields)
- return cmp_record(table,1);
+ return cmp_record(table,record[1]);
/* Compare null bits */
if (memcmp(table->null_flags,
table->null_flags+table->rec_buff_length,
@@ -201,14 +201,14 @@ int mysql_update(THD *thd,
bzero((char*) &tables,sizeof(tables));
tables.table = table;
- table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
order_num)||
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
- (table->found_records = filesort(thd, table, sortorder, length,
+ (table->sort.found_records = filesort(thd, table, sortorder, length,
(SQL_SELECT *) 0,
HA_POS_ERROR, &examined_rows))
== HA_POS_ERROR)
@@ -288,7 +288,7 @@ int mysql_update(THD *thd,
{
if (!(select && select->skipp_record()))
{
- store_record(table,1);
+ store_record(table,record[1]);
if (fill_record(fields,values) || thd->net.report_error)
break; /* purecov: inspected */
found++;
@@ -731,7 +731,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
if (table == table_to_update)
{
table->status|= STATUS_UPDATED;
- store_record(table,1);
+ store_record(table,record[1]);
if (fill_record(*fields_for_table[offset], *values_for_table[offset]))
DBUG_RETURN(1);
found++;
@@ -863,7 +863,7 @@ int multi_update::do_updates(bool from_send_error)
if ((local_error= table->file->rnd_pos(table->record[0], ref_pos)))
goto err;
table->status|= STATUS_UPDATED;
- store_record(table,1);
+ store_record(table,record[1]);
/* Copy data from temporary table to current table */
for (copy_field_ptr=copy_field;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 71035a75084..acbe07be332 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2174,12 +2174,12 @@ simple_expr:
| '@' ident_or_text SET_VAR expr
{
$$= new Item_func_set_user_var($2,$4);
- Lex->uncacheable();;
+ Lex->uncacheable();
}
| '@' ident_or_text
{
$$= new Item_func_get_user_var($2);
- Lex->uncacheable();;
+ Lex->uncacheable();
}
| '@' '@' opt_var_ident_type ident_or_text
{
@@ -2227,6 +2227,8 @@ simple_expr:
{ $$= new Item_func_conv_charset3($3,$7,$5); }
| DEFAULT '(' simple_ident ')'
{ $$= new Item_default_value($3); }
+ | VALUES '(' simple_ident ')'
+ { $$= new Item_insert_value($3); }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
| FUNC_ARG1 '(' expr ')'
@@ -2276,7 +2278,7 @@ simple_expr:
| ENCRYPT '(' expr ')'
{
$$= new Item_func_encrypt($3);
- Lex->uncacheable();;
+ Lex->uncacheable();
}
| ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_encrypt($3,$5); }
| DECODE_SYM '(' expr ',' TEXT_STRING_literal ')'
diff --git a/sql/structs.h b/sql/structs.h
index 77c852673d5..05ebdba7a37 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -104,6 +104,7 @@ typedef struct st_read_record { /* Parameter to read_record */
uint index;
byte *ref_pos; /* pointer to form->refpos */
byte *record;
+ byte *rec_buf; /* to read field values after filesort */
byte *cache,*cache_pos,*cache_end,*read_positions;
IO_CACHE *io_cache;
bool print_error, ignore_not_found_rows;
diff --git a/sql/table.cc b/sql/table.cc
index fda1fcb36e4..3aed75c7ac6 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -267,6 +267,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(ulong) (uint2korr(head+6)+uint2korr(head+14)),
MYF(MY_NABP)))
goto err_not_open; /* purecov: inspected */
+ /* HACK: table->record[2] is used instead of table->default_values here */
for (i=0 ; i < records ; i++, record+=rec_buff_length)
{
outparam->record[i]=(byte*) record;
@@ -276,11 +277,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (records == 2)
{ /* fix for select */
- outparam->record[2]=outparam->record[1];
+ outparam->default_values=outparam->record[1];
if (db_stat & HA_READ_ONLY)
outparam->record[1]=outparam->record[0]; /* purecov: inspected */
}
-
+ outparam->insert_values=0; /* for INSERT ... UPDATE */
+
VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
if (crypted)
diff --git a/sql/table.h b/sql/table.h
index 33e2db98d5a..2aefe23cb2f 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -44,6 +44,17 @@ typedef struct st_grant_info
enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2};
+typedef struct st_filesort_info
+{
+ IO_CACHE *io_cache; /* If sorted through filebyte */
+ byte *addon_buf; /* Pointer to a buffer if sorted with fields */
+ uint addon_length; /* Length of the buffer */
+ struct st_sort_addon_field *addon_field; /* Pointer to the fields info */
+ void (*unpack)(struct st_sort_addon_field *, byte *); /* To unpack back */
+ byte *record_pointers; /* If sorted in memory */
+ ha_rows found_records; /* How many records in sort */
+} FILESORT_INFO;
+
/* Table cache entry struct */
class Field_timestamp;
@@ -54,7 +65,9 @@ struct st_table {
Field **field; /* Pointer to fields */
Field_blob **blob_field; /* Pointer to blob fields */
HASH name_hash; /* hash of field names */
- byte *record[3]; /* Pointer to records */
+ byte *record[2]; /* Pointer to records */
+ byte *default_values; /* record with default values for INSERT */
+ byte *insert_values; /* used by INSERT ... UPDATE */
uint fields; /* field count */
uint reclength; /* Recordlength */
uint rec_buff_length;
@@ -120,9 +133,7 @@ struct st_table {
table_map map; /* ID bit of table (1,2,4,8,16...) */
ulong version,flush_version;
uchar *null_flags;
- IO_CACHE *io_cache; /* If sorted trough filebyte */
- byte *record_pointers; /* If sorted in memory */
- ha_rows found_records; /* How many records in sort */
+ FILESORT_INFO sort;
ORDER *group;
ha_rows quick_rows[MAX_KEY];
uint quick_key_parts[MAX_KEY];
@@ -135,10 +146,9 @@ struct st_table {
struct st_table_list *pos_in_table_list;
};
/* number of select if it is derived table */
- uint derived_select_number;
+ uint derived_select_number;
THD *in_use; /* Which thread uses this */
struct st_table *next,*prev;
- byte *default_values() { return record[2]; }
};
diff --git a/sql/uniques.cc b/sql/uniques.cc
index ed256a4b791..c6fb0f25643 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -95,12 +95,12 @@ bool Unique::flush()
bool Unique::get(TABLE *table)
{
SORTPARAM sort_param;
- table->found_records=elements+tree.elements_in_tree;
+ table->sort.found_records=elements+tree.elements_in_tree;
if (my_b_tell(&file) == 0)
{
/* Whole tree is in memory; Don't use disk if you don't need to */
- if ((record_pointers=table->record_pointers= (byte*)
+ if ((record_pointers=table->sort.record_pointers= (byte*)
my_malloc(tree.size_of_element * tree.elements_in_tree, MYF(0))))
{
(void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs,
@@ -112,7 +112,7 @@ bool Unique::get(TABLE *table)
if (flush())
return 1;
- IO_CACHE *outfile=table->io_cache;
+ IO_CACHE *outfile=table->sort.io_cache;
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
uint maxbuffer= file_ptrs.elements - 1;
uchar *sort_buffer;
@@ -120,8 +120,8 @@ bool Unique::get(TABLE *table)
bool error=1;
/* Open cached file if it isn't open */
- outfile=table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
- MYF(MY_ZEROFILL));
+ outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_ZEROFILL));
if (!outfile || ! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
diff --git a/sql/unireg.h b/sql/unireg.h
index 9430329e67a..ff942f6748a 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -57,7 +57,8 @@
#endif
#define MAX_FIELD_WIDTH 256 /* Max column width +1 */
-#define MAX_TABLES (sizeof(table_map)*8-1) /* Max tables in join */
+#define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */
+#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
#define MAX_FIELDS 4096 /* Limit in the .frm file */
@@ -103,13 +104,13 @@
#define SPECIAL_SAFE_MODE 2048
/* Extern defines */
-#define store_record(A,B) bmove_allign((A)->record[B],(A)->record[0],(size_t) (A)->reclength)
-#define restore_record(A,B) bmove_allign((A)->record[0],(A)->record[B],(size_t) (A)->reclength)
-#define cmp_record(A,B) memcmp((A)->record[0],(A)->record[B],(size_t) (A)->reclength)
+#define store_record(A,B) bmove_allign((A)->B,(A)->record[0],(size_t) (A)->reclength)
+#define restore_record(A,B) bmove_allign((A)->record[0],(A)->B,(size_t) (A)->reclength)
+#define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->reclength)
#define empty_record(A) { \
-bmove_allign((A)->record[0],(A)->record[2],(size_t) (A)->reclength); \
-bfill((A)->null_flags,(A)->null_bytes,255);\
-}
+ restore_record((A),default_values); \
+ bfill((A)->null_flags,(A)->null_bytes,255);\
+ }
/* Defines for use with openfrm, openprt and openfrd */