summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authormonty@mysql.com <>2005-11-05 01:32:55 +0200
committermonty@mysql.com <>2005-11-05 01:32:55 +0200
commita6f5375cb0cb40055f52e92d20ca04233ce70386 (patch)
tree4a7b533b6da471261f5c13c46e4e9f256ec63a0c /sql
parent3b74bb1b03a32616818f50f59cc44644036ab711 (diff)
parent303f6b4a7a44511aeb33ccbd9ff43ea2d454aa4c (diff)
downloadmariadb-git-a6f5375cb0cb40055f52e92d20ca04233ce70386.tar.gz
Merge mysql.com:/home/my/mysql-5.0
into mysql.com:/home/my/mysql-5.1
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am6
-rw-r--r--sql/field.cc67
-rw-r--r--sql/field.h15
-rw-r--r--sql/filesort.cc93
-rw-r--r--sql/ha_archive.cc78
-rw-r--r--sql/ha_archive.h5
-rw-r--r--sql/ha_berkeley.cc1
-rw-r--r--sql/ha_berkeley.h3
-rw-r--r--sql/ha_federated.cc96
-rw-r--r--sql/ha_innodb.cc78
-rw-r--r--sql/ha_myisam.cc13
-rw-r--r--sql/ha_ndbcluster.cc44
-rw-r--r--sql/handler.cc84
-rw-r--r--sql/handler.h3
-rw-r--r--sql/item.cc183
-rw-r--r--sql/item.h35
-rw-r--r--sql/item_cmpfunc.cc14
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/item_func.cc228
-rw-r--r--sql/item_geofunc.cc77
-rw-r--r--sql/item_strfunc.cc50
-rw-r--r--sql/item_strfunc.h9
-rw-r--r--sql/item_subselect.cc6
-rw-r--r--sql/item_subselect.h16
-rw-r--r--sql/item_sum.cc4
-rw-r--r--sql/item_timefunc.cc89
-rw-r--r--sql/item_timefunc.h2
-rw-r--r--sql/log.cc73
-rw-r--r--sql/log_event.cc309
-rw-r--r--sql/log_event.h129
-rw-r--r--sql/my_decimal.cc2
-rw-r--r--sql/my_decimal.h60
-rw-r--r--sql/mysql_priv.h19
-rw-r--r--sql/mysqld.cc187
-rw-r--r--sql/opt_range.cc111
-rw-r--r--sql/opt_range.h2
-rw-r--r--sql/parse_file.cc7
-rw-r--r--sql/password.c13
-rw-r--r--sql/protocol.cc4
-rw-r--r--sql/records.cc194
-rw-r--r--sql/repl_failsafe.cc1
-rw-r--r--sql/share/errmsg.txt5
-rw-r--r--sql/slave.cc170
-rw-r--r--sql/slave.h11
-rw-r--r--sql/sp.cc31
-rw-r--r--sql/sp_cache.cc2
-rw-r--r--sql/sp_head.cc51
-rw-r--r--sql/sp_rcontext.cc8
-rw-r--r--sql/sp_rcontext.h11
-rw-r--r--sql/spatial.cc324
-rw-r--r--sql/spatial.h19
-rw-r--r--sql/sql_acl.cc75
-rw-r--r--sql/sql_analyse.cc33
-rw-r--r--sql/sql_base.cc182
-rw-r--r--sql/sql_cache.cc21
-rw-r--r--sql/sql_class.cc21
-rw-r--r--sql/sql_class.h75
-rw-r--r--sql/sql_delete.cc58
-rw-r--r--sql/sql_derived.cc39
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_help.cc3
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc3
-rw-r--r--sql/sql_lex.h20
-rw-r--r--sql/sql_load.cc16
-rw-r--r--sql/sql_manager.cc12
-rw-r--r--sql/sql_parse.cc248
-rw-r--r--sql/sql_prepare.cc115
-rw-r--r--sql/sql_rename.cc7
-rw-r--r--sql/sql_repl.cc37
-rw-r--r--sql/sql_select.cc159
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_show.cc35
-rw-r--r--sql/sql_table.cc104
-rw-r--r--sql/sql_trigger.cc76
-rw-r--r--sql/sql_union.cc14
-rw-r--r--sql/sql_update.cc46
-rw-r--r--sql/sql_view.cc186
-rw-r--r--sql/sql_view.h4
-rw-r--r--sql/sql_yacc.yy96
-rw-r--r--sql/structs.h3
-rw-r--r--sql/table.cc335
-rw-r--r--sql/table.h50
-rw-r--r--sql/unireg.cc35
84 files changed, 3643 insertions, 1522 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index ada462f5e09..98d4d6b3d3a 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -22,7 +22,8 @@ MYSQLBASEdir= $(prefix)
INCLUDES = @ZLIB_INCLUDES@ \
@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
-I$(top_builddir)/include -I$(top_srcdir)/include \
- -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes)
+ -I$(top_srcdir)/regex -I$(srcdir) $(yassl_includes) \
+ $(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
@@ -42,7 +43,8 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
@bdb_libs@ @innodb_libs@ @pstack_libs@ \
@innodb_system_libs@ \
@ndbcluster_libs@ @ndbcluster_system_libs@ \
- $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@
+ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \
+ @yassl_libs@ @openssl_libs@
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.h \
item_create.h item_subselect.h item_row.h \
diff --git a/sql/field.cc b/sql/field.cc
index d334dc1ab53..ef4d9429bda 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1630,6 +1630,7 @@ bool Field::needs_quotes(void)
case FIELD_TYPE_MEDIUM_BLOB :
case FIELD_TYPE_LONG_BLOB :
case FIELD_TYPE_GEOMETRY :
+ case FIELD_TYPE_BIT:
DBUG_RETURN(1);
case FIELD_TYPE_DECIMAL :
@@ -5883,7 +5884,8 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
memcpy(ptr,from,copy_length);
if (copy_length < field_length) // Append spaces if shorter
field_charset->cset->fill(field_charset,ptr+copy_length,
- field_length-copy_length,' ');
+ field_length-copy_length,
+ field_charset->pad_char);
if ((copy_length < length) && table->in_use->count_cuted_fields)
{ // Check if we loosed some info
@@ -6426,6 +6428,17 @@ int Field_varstring::key_cmp(const byte *a,const byte *b)
void Field_varstring::sort_string(char *to,uint length)
{
uint tot_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+
+ if (field_charset == &my_charset_bin)
+ {
+ /* Store length last in high-byte order to sort longer strings first */
+ if (length_bytes == 1)
+ to[length-1]= tot_length;
+ else
+ mi_int2store(to+length-2, tot_length);
+ length-= length_bytes;
+ }
+
tot_length= my_strnxfrm(field_charset,
(uchar*) to, length,
(uchar*) ptr + length_bytes,
@@ -7073,8 +7086,7 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type)
return;
}
get_ptr(&blob);
- gobj= Geometry::create_from_wkb(&buffer,
- blob + SRID_SIZE, blob_length - SRID_SIZE);
+ gobj= Geometry::construct(&buffer, blob, blob_length);
if (gobj->get_mbr(&mbr, &dummy))
bzero(buff, SIZEOF_STORED_DOUBLE*4);
else
@@ -7136,6 +7148,13 @@ int Field_blob::key_cmp(const byte *a,const byte *b)
}
+uint32 Field_blob::sort_length() const
+{
+ return (uint32) (current_thd->variables.max_sort_length +
+ (field_charset == &my_charset_bin ? 0 : packlength));
+}
+
+
void Field_blob::sort_string(char *to,uint length)
{
char *blob;
@@ -7145,6 +7164,31 @@ void Field_blob::sort_string(char *to,uint length)
bzero(to,length);
else
{
+ if (field_charset == &my_charset_bin)
+ {
+ char *pos;
+
+ /*
+ Store length of blob last in blob to shorter blobs before longer blobs
+ */
+ length-= packlength;
+ pos= to+length;
+
+ switch (packlength) {
+ case 1:
+ *pos= (char) blob_length;
+ break;
+ case 2:
+ mi_int2store(pos, blob_length);
+ break;
+ case 3:
+ mi_int3store(pos, blob_length);
+ break;
+ case 4:
+ mi_int4store(pos, blob_length);
+ break;
+ }
+ }
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
blob_length=my_strnxfrm(field_charset,
@@ -7371,8 +7415,7 @@ void Field_geom::get_key_image(char *buff, uint length, imagetype type)
return;
}
get_ptr(&blob);
- gobj= Geometry::create_from_wkb(&buffer,
- blob + SRID_SIZE, blob_length - SRID_SIZE);
+ gobj= Geometry::construct(&buffer, blob, blob_length);
if (gobj->get_mbr(&mbr, &dummy))
bzero(buff, SIZEOF_STORED_DOUBLE*4);
else
@@ -7453,7 +7496,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
uint32 wkb_type;
if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2)
goto err;
- wkb_type= uint4korr(from + WKB_HEADER_SIZE);
+ wkb_type= uint4korr(from + SRID_SIZE + 1);
if (wkb_type < (uint32) Geometry::wkb_point ||
wkb_type > (uint32) Geometry::wkb_end)
goto err;
@@ -8226,8 +8269,20 @@ void Field_bit_as_char::sql_type(String &res) const
Handling of field and create_field
*****************************************************************************/
+/*
+ Convert create_field::length from number of characters to number of bytes
+
+ SYNOPSIS
+ create_field::create_length_to_internal_length()
+
+ DESCRIPTION
+ Convert create_field::length from number of characters to number of bytes,
+ save original value in chars_length.
+*/
+
void create_field::create_length_to_internal_length(void)
{
+ chars_length= length;
switch (sql_type) {
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
diff --git a/sql/field.h b/sql/field.h
index 3833f764787..77d00b671f6 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -137,6 +137,7 @@ public:
virtual bool eq_def(Field *field);
virtual uint32 pack_length() const { return (uint32) field_length; }
virtual uint32 pack_length_in_rec() const { return pack_length(); }
+ virtual uint32 sort_length() const { return pack_length(); }
virtual void reset(void) { bzero(ptr,pack_length()); }
virtual void reset_fields() {}
virtual void set_default()
@@ -1065,6 +1066,11 @@ public:
void reset(void) { bzero(ptr,field_length+length_bytes); }
uint32 pack_length() const { return (uint32) field_length+length_bytes; }
uint32 key_length() const { return (uint32) field_length; }
+ uint32 sort_length() const
+ {
+ return (uint32) field_length + (field_charset == &my_charset_bin ?
+ length_bytes : 0);
+ }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(longlong nr, bool unsigned_val);
int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */
@@ -1144,6 +1150,7 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const
{ return (uint32) (packlength+table->s->blob_ptr_size); }
+ uint32 sort_length() const;
inline uint32 max_data_length() const
{
return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
@@ -1390,7 +1397,15 @@ public:
LEX_STRING comment; // Comment for field
Item *def; // Default value
enum enum_field_types sql_type;
+ /*
+ At various stages in execution this can be length of field in bytes or
+ max number of characters.
+ */
ulong length;
+ /*
+ The value of 'length' before a call to create_length_to_internal_length
+ */
+ uint32 chars_length;
uint decimals, flags, pack_length, key_length;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
diff --git a/sql/filesort.cc b/sql/filesort.cc
index ad784c729fa..42d25dbbaee 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -50,7 +50,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
IO_CACHE *outfile);
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count,
FILESORT_INFO *table_sort);
-static uint sortlength(SORT_FIELD *sortorder, uint s_length,
+static uint suffix_length(ulong string_length);
+static uint sortlength(THD *thd, 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);
@@ -123,7 +124,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
sort_keys= (uchar **) NULL;
error= 1;
bzero((char*) &param,sizeof(param));
- param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
+ param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset);
param.ref_length= table->file->ref_length;
param.addon_field= 0;
param.addon_length= 0;
@@ -585,6 +586,28 @@ err:
} /* write_keys */
+/*
+ Store length as suffix in high-byte-first order
+*/
+
+static inline void store_length(uchar *to, uint length, uint pack_length)
+{
+ switch (pack_length) {
+ case 1:
+ *to= (uchar) length;
+ break;
+ case 2:
+ mi_int2store(to, length);
+ break;
+ case 3:
+ mi_int3store(to, length);
+ default:
+ mi_int4store(to, length);
+ break;
+ }
+}
+
+
/* makes a sort-key from record */
static void make_sortkey(register SORTPARAM *param,
@@ -623,9 +646,11 @@ static void make_sortkey(register SORTPARAM *param,
maybe_null= item->maybe_null;
switch (sort_field->result_type) {
case STRING_RESULT:
- {
+ {
CHARSET_INFO *cs=item->collation.collation;
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
+ int diff;
+ uint sort_field_length;
if (maybe_null)
*to++=1;
@@ -644,24 +669,32 @@ static void make_sortkey(register SORTPARAM *param,
}
break;
}
- length=res->length();
- int diff=(int) (sort_field->length-length);
+ length= res->length();
+ sort_field_length= sort_field->length - sort_field->suffix_length;
+ diff=(int) (sort_field_length - length);
if (diff < 0)
{
diff=0; /* purecov: inspected */
- length=sort_field->length;
+ length= sort_field_length;
}
+ if (sort_field->suffix_length)
+ {
+ /* Store length last in result_string */
+ store_length(to + sort_field_length, length,
+ sort_field->suffix_length);
+ }
if (sort_field->need_strxnfrm)
{
char *from=(char*) res->ptr();
+ uint tmp_length;
if ((unsigned char *)from == to)
{
set_if_smaller(length,sort_field->length);
memcpy(param->tmp_buffer,from,length);
from=param->tmp_buffer;
}
- uint tmp_length=my_strnxfrm(cs,to,sort_field->length,
- (unsigned char *) from, length);
+ tmp_length= my_strnxfrm(cs,to,sort_field->length,
+ (unsigned char *) from, length);
DBUG_ASSERT(tmp_length == sort_field->length);
}
else
@@ -670,7 +703,7 @@ static void make_sortkey(register SORTPARAM *param,
cs->cset->fill(cs, (char *)to+length,diff,fill_char);
}
break;
- }
+ }
case INT_RESULT:
{
longlong value= item->val_int_result();
@@ -1170,11 +1203,25 @@ static int merge_index(SORTPARAM *param, uchar *sort_buffer,
} /* merge_index */
+static uint suffix_length(ulong string_length)
+{
+ if (string_length < 256)
+ return 1;
+ if (string_length < 256L*256L)
+ return 2;
+ if (string_length < 256L*256L*256L)
+ return 3;
+ return 4; // Can't sort longer than 4G
+}
+
+
+
/*
Calculate length of sort key
SYNOPSIS
sortlength()
+ thd Thread handler
sortorder Order of items to sort
uint s_length Number of items to sort
multi_byte_charset (out)
@@ -1190,10 +1237,10 @@ static int merge_index(SORTPARAM *param, uchar *sort_buffer,
*/
static uint
-sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
+sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
+ bool *multi_byte_charset)
{
reg2 uint length;
- THD *thd= current_thd;
CHARSET_INFO *cs;
*multi_byte_charset= 0;
@@ -1201,19 +1248,17 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
for (; s_length-- ; sortorder++)
{
sortorder->need_strxnfrm= 0;
+ sortorder->suffix_length= 0;
if (sortorder->field)
{
- if (sortorder->field->type() == FIELD_TYPE_BLOB)
- sortorder->length= thd->variables.max_sort_length;
- else
+ cs= sortorder->field->sort_charset();
+ sortorder->length= sortorder->field->sort_length();
+
+ if (use_strnxfrm((cs=sortorder->field->sort_charset())))
{
- sortorder->length=sortorder->field->pack_length();
- if (use_strnxfrm((cs=sortorder->field->sort_charset())))
- {
- sortorder->need_strxnfrm= 1;
- *multi_byte_charset= 1;
- sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
- }
+ sortorder->need_strxnfrm= 1;
+ *multi_byte_charset= 1;
+ sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
}
if (sortorder->field->maybe_null())
length++; // Place for NULL marker
@@ -1229,6 +1274,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1;
}
+ else if (cs == &my_charset_bin)
+ {
+ /* Store length last to be able to sort blob/varbinary */
+ sortorder->suffix_length= suffix_length(sortorder->length);
+ sortorder->length+= sortorder->suffix_length;
+ }
break;
case INT_RESULT:
#if SIZEOF_LONG_LONG > 4
diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc
index 59c56e80cc3..c4801de5fb2 100644
--- a/sql/ha_archive.cc
+++ b/sql/ha_archive.cc
@@ -453,7 +453,6 @@ int ha_archive::free_share(ARCHIVE_SHARE *share)
*/
static const char *ha_archive_exts[] = {
ARZ,
- ARN,
ARM,
NullS
};
@@ -1053,4 +1052,81 @@ int ha_archive::delete_all_rows()
DBUG_ENTER("ha_archive::delete_all_rows");
DBUG_RETURN(0);
}
+
+/*
+ We just return state if asked.
+*/
+bool ha_archive::is_crashed() const
+{
+ return share->crashed;
+}
+
+/*
+ Simple scan of the tables to make sure everything is ok.
+*/
+
+int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int rc= 0;
+ byte *buf;
+ const char *old_proc_info=thd->proc_info;
+ ha_rows count= share->rows_recorded;
+ DBUG_ENTER("ha_archive::check");
+
+ thd->proc_info= "Checking table";
+ /* Flush any waiting data */
+ gzflush(share->archive_write, Z_SYNC_FLUSH);
+
+ /*
+ First we create a buffer that we can use for reading rows, and can pass
+ to get_row().
+ */
+ if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
+ rc= HA_ERR_OUT_OF_MEM;
+
+ /*
+ Now we will rewind the archive file so that we are positioned at the
+ start of the file.
+ */
+ if (!rc)
+ read_data_header(archive);
+
+ if (!rc)
+ while (!(rc= get_row(archive, buf)))
+ count--;
+
+ my_free((char*)buf, MYF(0));
+
+ thd->proc_info= old_proc_info;
+
+ if ((rc && rc != HA_ERR_END_OF_FILE) || count)
+ {
+ share->crashed= FALSE;
+ DBUG_RETURN(HA_ADMIN_CORRUPT);
+ }
+ else
+ {
+ DBUG_RETURN(HA_ADMIN_OK);
+ }
+}
+
+/*
+ Check and repair the table if needed.
+*/
+bool ha_archive::check_and_repair(THD *thd)
+{
+ HA_CHECK_OPT check_opt;
+ DBUG_ENTER("ha_archive::check_and_repair");
+
+ check_opt.init();
+
+ if (check(thd, &check_opt) == HA_ADMIN_CORRUPT)
+ {
+ DBUG_RETURN(repair(thd, &check_opt));
+ }
+ else
+ {
+ DBUG_RETURN(HA_ADMIN_OK);
+ }
+}
#endif /* HAVE_ARCHIVE_DB */
diff --git a/sql/ha_archive.h b/sql/ha_archive.h
index 849b5b5bd6c..56a4b9d1e27 100644
--- a/sql/ha_archive.h
+++ b/sql/ha_archive.h
@@ -68,7 +68,7 @@ public:
ulong table_flags() const
{
return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | HA_NO_AUTO_INCREMENT |
- HA_FILE_BASED | HA_CAN_INSERT_DELAYED);
+ HA_FILE_BASED | HA_CAN_INSERT_DELAYED | HA_CAN_GEOMETRY);
}
ulong index_flags(uint idx, uint part, bool all_parts) const
{
@@ -103,6 +103,9 @@ public:
}
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
+ bool is_crashed() const;
+ int check(THD* thd, HA_CHECK_OPT* check_opt);
+ bool check_and_repair(THD *thd);
};
bool archive_db_init(void);
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 3312b60e6c4..fa8cda44866 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -394,6 +394,7 @@ ha_berkeley::ha_berkeley(TABLE *table_arg)
int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT |
HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
+ HA_CAN_GEOMETRY |
HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
changed_rows(0), last_dup_key((uint) -1), version(0), using_ignore(0)
{}
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index 95ff64a082a..b3ce72d374b 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -94,6 +94,9 @@ class ha_berkeley: public handler
uint max_supported_keys() const { return MAX_KEY-1; }
uint extra_rec_buf_length() const { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
ha_rows estimate_rows_upper_bound();
+ uint max_supported_key_length() const { return UINT_MAX32; }
+ uint max_supported_key_part_length() const { return UINT_MAX32; }
+
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
bool has_transactions() { return 1;}
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 66c2431844d..703646f8bf3 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -480,6 +480,7 @@ static int check_foreign_data_source(
String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
MYSQL *mysql;
DBUG_ENTER("ha_federated::check_foreign_data_source");
+
/* Zero the length, otherwise the string will have misc chars */
query.length(0);
@@ -564,6 +565,7 @@ static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num)
char buf[FEDERATED_QUERY_BUFFER_SIZE];
int buf_len;
DBUG_ENTER("ha_federated parse_url_error");
+
if (share->scheme)
{
DBUG_PRINT("info",
@@ -572,11 +574,9 @@ static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num)
my_free((gptr) share->scheme, MYF(0));
share->scheme= 0;
}
- buf_len= (table->s->connect_string.length > (FEDERATED_QUERY_BUFFER_SIZE - 1))
- ? FEDERATED_QUERY_BUFFER_SIZE - 1 : table->s->connect_string.length;
-
- strnmov(buf, table->s->connect_string.str, buf_len);
- buf[buf_len]= '\0';
+ buf_len= min(table->s->connect_string.length,
+ FEDERATED_QUERY_BUFFER_SIZE-1);
+ strmake(buf, table->s->connect_string.str, buf_len);
my_error(error_num, MYF(0), buf);
DBUG_RETURN(error_num);
}
@@ -767,12 +767,9 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
{
ulong *lengths;
Field **field;
-
DBUG_ENTER("ha_federated::convert_row_to_internal_format");
- // num_fields= mysql_num_fields(stored_result);
lengths= mysql_fetch_lengths(stored_result);
-
memset(record, 0, table->s->null_bytes);
for (field= table->field; *field; field++)
@@ -824,13 +821,8 @@ static bool emit_key_part_element(String *to, KEY_PART_INFO *part,
*buf++= '0';
*buf++= 'x';
- for (; len; ptr++,len--)
- {
- uint tmp= (uint)(uchar) *ptr;
- *buf++= _dig_vec_upper[tmp >> 4];
- *buf++= _dig_vec_upper[tmp & 15];
- }
- if (to->append(buff, (uint)(buf - buff)))
+ buf= octet2hex(buf, (char*) ptr, len);
+ if (to->append((char*) buff, (uint)(buf - buff)))
DBUG_RETURN(1);
}
else if (part->key_part_flag & HA_BLOB_PART)
@@ -1127,8 +1119,8 @@ bool ha_federated::create_where_from_key(String *to,
char tmpbuff[FEDERATED_QUERY_BUFFER_SIZE];
String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info);
const key_range *ranges[2]= { start_key, end_key };
-
DBUG_ENTER("ha_federated::create_where_from_key");
+
tmp.length(0);
if (start_key == NULL && end_key == NULL)
DBUG_RETURN(1);
@@ -1177,6 +1169,7 @@ bool ha_federated::create_where_from_key(String *to,
switch(ranges[i]->flag) {
case(HA_READ_KEY_EXACT):
+ DBUG_PRINT("info", ("federated HA_READ_KEY_EXACT %d", i));
if (store_length >= length ||
!needs_quotes ||
key_part->type == HA_KEYTYPE_BIT ||
@@ -1211,6 +1204,7 @@ bool ha_federated::create_where_from_key(String *to,
}
break;
case(HA_READ_AFTER_KEY):
+ DBUG_PRINT("info", ("federated HA_READ_AFTER_KEY %d", i));
if (store_length >= length) /* end key */
{
if (emit_key_part_name(&tmp, key_part))
@@ -1235,6 +1229,7 @@ bool ha_federated::create_where_from_key(String *to,
break;
}
case(HA_READ_KEY_OR_NEXT):
+ DBUG_PRINT("info", ("federated HA_READ_KEY_OR_NEXT %d", i));
if (emit_key_part_name(&tmp, key_part) ||
tmp.append(FEDERATED_GE) ||
emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
@@ -1242,6 +1237,7 @@ bool ha_federated::create_where_from_key(String *to,
DBUG_RETURN(1);
break;
case(HA_READ_BEFORE_KEY):
+ DBUG_PRINT("info", ("federated HA_READ_BEFORE_KEY %d", i));
if (store_length >= length)
{
if (emit_key_part_name(&tmp, key_part) ||
@@ -1252,6 +1248,7 @@ bool ha_federated::create_where_from_key(String *to,
break;
}
case(HA_READ_KEY_OR_PREV):
+ DBUG_PRINT("info", ("federated HA_READ_KEY_OR_PREV %d", i));
if (emit_key_part_name(&tmp, key_part) ||
tmp.append(FEDERATED_LE) ||
emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
@@ -1334,7 +1331,6 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query.append(FEDERATED_FROM);
query.append(FEDERATED_BTICK);
-
if (!(share= (FEDERATED_SHARE *)
my_multi_malloc(MYF(MY_WME),
&share, sizeof(*share),
@@ -1389,8 +1385,8 @@ error:
static int free_share(FEDERATED_SHARE *share)
{
DBUG_ENTER("free_share");
- pthread_mutex_lock(&federated_mutex);
+ pthread_mutex_lock(&federated_mutex);
if (!--share->use_count)
{
hash_delete(&federated_open_tables, (byte*) share);
@@ -1578,7 +1574,6 @@ int ha_federated::write_row(byte *buf)
values_string.length(0);
insert_string.length(0);
insert_field_value_string.length(0);
-
DBUG_ENTER("ha_federated::write_row");
DBUG_PRINT("info",
("table charset name %s csname %s",
@@ -1683,7 +1678,6 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt)
{
char query_buffer[STRING_BUFFER_USUAL_SIZE];
String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
-
DBUG_ENTER("ha_federated::optimize");
query.length(0);
@@ -1707,7 +1701,6 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt)
{
char query_buffer[STRING_BUFFER_USUAL_SIZE];
String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
-
DBUG_ENTER("ha_federated::repair");
query.length(0);
@@ -1753,14 +1746,16 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt)
int ha_federated::update_row(const byte *old_data, byte *new_data)
{
/*
- This used to control how the query was built. If there was a primary key,
- the query would be built such that there was a where clause with only
- that column as the condition. This is flawed, because if we have a multi-part
- primary key, it would only use the first part! We don't need to do this anyway,
- because read_range_first will retrieve the correct record, which is what is used
- to build the WHERE clause. We can however use this to append a LIMIT to the end
- if there is NOT a primary key. Why do this? Because we only are updating one
- record, and LIMIT enforces this.
+ This used to control how the query was built. If there was a
+ primary key, the query would be built such that there was a where
+ clause with only that column as the condition. This is flawed,
+ because if we have a multi-part primary key, it would only use the
+ first part! We don't need to do this anyway, because
+ read_range_first will retrieve the correct record, which is what
+ is used to build the WHERE clause. We can however use this to
+ append a LIMIT to the end if there is NOT a primary key. Why do
+ this? Because we only are updating one record, and LIMIT enforces
+ this.
*/
bool has_a_primary_key= (table->s->primary_key == 0 ? TRUE : FALSE);
/*
@@ -1787,7 +1782,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
String where_string(where_buffer,
sizeof(where_buffer),
&my_charset_bin);
-
DBUG_ENTER("ha_federated::update_row");
/*
set string lengths to 0 to avoid misc chars in string
@@ -1982,12 +1976,10 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
sizeof(sql_query_buffer),
&my_charset_bin);
key_range range;
+ DBUG_ENTER("ha_federated::index_read_idx");
index_string.length(0);
sql_query.length(0);
-
- DBUG_ENTER("ha_federated::index_read_idx");
-
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
@@ -2076,8 +2068,8 @@ int ha_federated::read_range_first(const key_range *start_key,
String sql_query(sql_query_buffer,
sizeof(sql_query_buffer),
&my_charset_bin);
-
DBUG_ENTER("ha_federated::read_range_first");
+
if (start_key == NULL && end_key == NULL)
DBUG_RETURN(0);
@@ -2392,7 +2384,6 @@ void ha_federated::info(uint flag)
MYSQL_RES *result= 0;
MYSQL_ROW row;
String status_query_string(status_buf, sizeof(status_buf), &my_charset_bin);
-
DBUG_ENTER("ha_federated::info");
error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
@@ -2483,10 +2474,10 @@ error:
int ha_federated::delete_all_rows()
{
- DBUG_ENTER("ha_federated::delete_all_rows");
-
char query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
+ DBUG_ENTER("ha_federated::delete_all_rows");
+
query.length(0);
query.set_charset(system_charset_info);
@@ -2498,11 +2489,12 @@ int ha_federated::delete_all_rows()
/*
TRUNCATE won't return anything in mysql_affected_rows
*/
- deleted+= records;
if (mysql_real_query(mysql, query.ptr(), query.length()))
{
DBUG_RETURN(stash_remote_error());
}
+ deleted+= records;
+ records= 0;
DBUG_RETURN(0);
}
@@ -2581,32 +2573,14 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
int ha_federated::create(const char *name, TABLE *table_arg,
HA_CREATE_INFO *create_info)
{
- int retval= 0;
- /*
- only a temporary share, to test the url
- */
- FEDERATED_SHARE tmp_share;
+ int retval;
+ FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url
DBUG_ENTER("ha_federated::create");
- if ((retval= parse_url(&tmp_share, table_arg, 1)))
- goto error;
-
- if ((retval= check_foreign_data_source(&tmp_share, 1)))
- goto error;
-
- if (tmp_share.scheme)
- {
- my_free((gptr) tmp_share.scheme, MYF(0));
- tmp_share.scheme= 0;
- }
- DBUG_RETURN(retval);
+ if (!(retval= parse_url(&tmp_share, table_arg, 1)))
+ retval= check_foreign_data_source(&tmp_share, 1);
-error:
- if (tmp_share.scheme)
- {
- my_free((gptr) tmp_share.scheme, MYF(0));
- tmp_share.scheme= 0;
- }
+ my_free((gptr) tmp_share.scheme, MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN(retval);
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 12f8b984971..1fdc36c84fe 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -812,6 +812,7 @@ ha_innobase::ha_innobase(TABLE *table_arg)
HA_CAN_SQL_HANDLER |
HA_NOT_EXACT_COUNT |
HA_PRIMARY_KEY_IN_READ_INDEX |
+ HA_CAN_GEOMETRY |
HA_TABLE_SCAN_ON_INDEX),
last_dup_key((uint) -1),
start_of_scan(0),
@@ -2757,6 +2758,7 @@ get_innobase_type_from_mysql_type(
return(DATA_DOUBLE);
case FIELD_TYPE_DECIMAL:
return(DATA_DECIMAL);
+ case FIELD_TYPE_GEOMETRY:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_BLOB:
@@ -2872,6 +2874,9 @@ ha_innobase::store_key_val_for_row(
ulint lenlen;
ulint len;
byte* data;
+ ulint key_len;
+ CHARSET_INFO* cs;
+ int error=0;
if (is_null) {
buff += key_part->length + 2;
@@ -2890,8 +2895,20 @@ ha_innobase::store_key_val_for_row(
/* In a column prefix index, we may need to truncate
the stored value: */
- if (len > key_part->length) {
- len = key_part->length;
+ cs = key_part->field->charset();
+
+ if (cs->mbmaxlen > 1 && key_part->length > 0) {
+ key_len = (ulint) cs->cset->well_formed_len(cs,
+ (const char *) data,
+ (const char *) data + key_part->length,
+ key_part->length / cs->mbmaxlen,
+ &error);
+ } else {
+ key_len = key_part->length;
+ }
+
+ if (len > key_len) {
+ len = key_len;
}
/* The length in a key value is always stored in 2
@@ -2915,6 +2932,11 @@ ha_innobase::store_key_val_for_row(
|| mysql_type == FIELD_TYPE_BLOB
|| mysql_type == FIELD_TYPE_LONG_BLOB) {
+ CHARSET_INFO* cs;
+ ulint key_len;
+ ulint len;
+ int error=0;
+
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
if (is_null) {
@@ -2935,8 +2957,21 @@ ha_innobase::store_key_val_for_row(
indexes, and we may need to truncate the data to be
stored in the key value: */
- if (blob_len > key_part->length) {
- blob_len = key_part->length;
+ cs = key_part->field->charset();
+
+ if (cs->mbmaxlen > 1 && key_part->length > 0) {
+ key_len = (ulint) cs->cset->well_formed_len(cs,
+ (const char *) blob_data,
+ (const char *) blob_data
+ + key_part->length,
+ key_part->length / cs->mbmaxlen,
+ &error);
+ } else {
+ key_len = key_part->length;
+ }
+
+ if (blob_len > key_len) {
+ blob_len = key_len;
}
/* MySQL reserves 2 bytes for the length and the
@@ -2958,15 +2993,40 @@ ha_innobase::store_key_val_for_row(
value we store may be also in a column prefix
index. */
+ CHARSET_INFO* cs;
+ ulint len;
+ const mysql_byte* src_start;
+ int error=0;
+
if (is_null) {
buff += key_part->length;
continue;
}
- memcpy(buff, record + key_part->offset,
- key_part->length);
- buff += key_part->length;
+ cs = key_part->field->charset();
+ src_start = record + key_part->offset;
+
+ if (key_part->length > 0 && cs->mbmaxlen > 1) {
+ len = (ulint) cs->cset->well_formed_len(cs,
+ src_start,
+ src_start + key_part->length,
+ key_part->length / cs->mbmaxlen,
+ &error);
+ } else {
+ len = key_part->length;
+ }
+
+ memcpy(buff, src_start, len);
+ buff+=len;
+
+ /* Pad the unused space with spaces */
+
+ if (len < key_part->length) {
+ len = key_part->length - len;
+ memset(buff, ' ', len);
+ buff+=len;
+ }
}
}
@@ -6755,6 +6815,7 @@ ha_innobase::store_lock(
|| thd->lex->sql_command == SQLCOM_CALL)
&& !thd->tablespace_op
&& thd->lex->sql_command != SQLCOM_TRUNCATE
+ && thd->lex->sql_command != SQLCOM_OPTIMIZE
&& thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
lock_type = TL_WRITE_ALLOW_WRITE;
@@ -7044,8 +7105,7 @@ ha_innobase::cmp_ref(
(const char*)ref1, len1,
(const char*)ref2, len2);
} else {
- result = field->key_cmp((const char*)ref1,
- (const char*)ref2);
+ result = field->key_cmp(ref1, ref2);
}
if (result) {
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 689dbf2fc24..03ef362c0d4 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -40,7 +40,7 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
myisam_recover_names, NULL};
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
- NullS};
+ "nulls_ignored", NullS};
TYPELIB myisam_stats_method_typelib= {
array_elements(myisam_stats_method_names) - 1, "",
myisam_stats_method_names, NULL};
@@ -985,11 +985,16 @@ int ha_myisam::enable_indexes(uint mode)
{
sql_print_warning("Warning: Enabling keys got errno %d, retrying",
my_errno);
- thd->clear_error();
+ /* Repairing by sort failed. Now try standard repair method. */
param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
error= (repair(thd,param,0) != HA_ADMIN_OK);
- if (!error && thd->net.report_error)
- error= HA_ERR_CRASHED;
+ /*
+ If the standard repair succeeded, clear all error messages which
+ might have been set by the first repair. They can still be seen
+ with SHOW WARNINGS then.
+ */
+ if (! error)
+ thd->clear_error();
}
info(HA_STATUS_CONST);
thd->proc_info=save_proc_info;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 50d9f5b701a..2340cc006f6 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -599,9 +599,9 @@ static bool ndb_supported_type(enum_field_types type)
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_GEOMETRY:
return TRUE;
case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_GEOMETRY:
break;
}
return FALSE;
@@ -3216,7 +3216,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
if (!thd_ndb->lock_count++)
{
PRINT_OPTION_FLAGS(thd);
- if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK)))
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
// Autocommit transaction
DBUG_ASSERT(!thd_ndb->stmt);
@@ -3388,11 +3388,11 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
}
/*
- When using LOCK TABLE's external_lock is only called when the actual
- TABLE LOCK is done.
- Under LOCK TABLES, each used tables will force a call to start_stmt.
- Ndb doesn't currently support table locks, and will do ordinary
- startTransaction for each transaction/statement.
+ Start a transaction for running a statement if one is not
+ already running in a transaction. This will be the case in
+ a BEGIN; COMMIT; block
+ When using LOCK TABLE's external_lock will start a transaction
+ since ndb does not currently does not support table locking
*/
int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
@@ -3402,17 +3402,10 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
PRINT_OPTION_FLAGS(thd);
Thd_ndb *thd_ndb= get_thd_ndb(thd);
- NdbTransaction *trans= thd_ndb->stmt;
+ NdbTransaction *trans= (thd_ndb->stmt)?thd_ndb->stmt:thd_ndb->all;
if (!trans){
Ndb *ndb= thd_ndb->ndb;
DBUG_PRINT("trans",("Starting transaction stmt"));
-
-#if 0
- NdbTransaction *tablock_trans= thd_ndb->all;
- DBUG_PRINT("info", ("tablock_trans: %x", (UintPtr)tablock_trans));
- DBUG_ASSERT(tablock_trans);
-// trans= ndb->hupp(tablock_trans);
-#endif
trans= ndb->startTransaction();
if (trans == NULL)
ERR_RETURN(ndb->getNdbError());
@@ -3709,6 +3702,7 @@ static int create_ndb_column(NDBCOL &col,
col.setStripeSize(0);
break;
//mysql_type_blob:
+ case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_BLOB:
if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
col.setType(NDBCOL::Blob);
@@ -3774,7 +3768,6 @@ static int create_ndb_column(NDBCOL &col,
break;
}
case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_GEOMETRY:
goto mysql_type_unsupported;
mysql_type_unsupported:
default:
@@ -3806,7 +3799,8 @@ int ha_ndbcluster::create(const char *name,
uint pack_length, length, i, pk_length= 0;
const void *data, *pack_data;
char name2[FN_HEADLEN];
- bool create_from_engine= (info->table_options & HA_CREATE_FROM_ENGINE);
+ bool create_from_engine= test(info->table_options &
+ HA_OPTION_CREATE_FROM_ENGINE);
DBUG_ENTER("ha_ndbcluster::create");
DBUG_PRINT("enter", ("name: %s", name));
@@ -3876,6 +3870,7 @@ int ha_ndbcluster::create(const char *name,
* 5 - from extra words added by tup/dict??
*/
switch (form->field[i]->real_type()) {
+ case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
@@ -4140,7 +4135,12 @@ ulonglong ha_ndbcluster::get_auto_increment()
--retries &&
ndb->getNdbError().status == NdbError::TemporaryError);
if (auto_value == NDB_FAILED_AUTO_INCREMENT)
- ERR_RETURN(ndb->getNdbError());
+ {
+ const NdbError err= ndb->getNdbError();
+ sql_print_error("Error %lu in ::get_auto_increment(): %s",
+ (ulong) err.code, err.message);
+ DBUG_RETURN(~(ulonglong) 0);
+ }
DBUG_RETURN((longlong)auto_value);
}
@@ -4161,6 +4161,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
HA_AUTO_PART_KEY |
HA_NO_PREFIX_CHAR_KEYS |
HA_NEED_READ_RANGE_BUFFER |
+ HA_CAN_GEOMETRY |
HA_CAN_BIT_FIELD),
m_share(0),
m_part_info(NULL),
@@ -6008,7 +6009,6 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
{
THD *thd; /* needs to be first for thread_stack */
Ndb* ndb;
- int error= 0;
struct timespec abstime;
my_thread_init();
@@ -6037,9 +6037,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
{
pthread_mutex_lock(&LOCK_ndb_util_thread);
- error= pthread_cond_timedwait(&COND_ndb_util_thread,
- &LOCK_ndb_util_thread,
- &abstime);
+ pthread_cond_timedwait(&COND_ndb_util_thread,
+ &LOCK_ndb_util_thread,
+ &abstime);
pthread_mutex_unlock(&LOCK_ndb_util_thread);
DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %d",
diff --git a/sql/handler.cc b/sql/handler.cc
index 5b07c9e9c24..1ec4ddf17b7 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -186,15 +186,18 @@ enum db_type ha_resolve_by_name(const char *name, uint namelen)
THD *thd= current_thd;
show_table_alias_st *table_alias;
handlerton **types;
- const char *ptr= name;
- if (thd && !my_strcasecmp(&my_charset_latin1, ptr, "DEFAULT"))
+ if (thd && !my_strnncoll(&my_charset_latin1,
+ (const uchar *)name, namelen,
+ (const uchar *)"DEFAULT", 7))
return (enum db_type) thd->variables.table_type;
retest:
for (types= sys_table_types; *types; types++)
{
- if (!my_strcasecmp(&my_charset_latin1, ptr, (*types)->name))
+ if (!my_strnncoll(&my_charset_latin1,
+ (const uchar *)name, namelen,
+ (const uchar *)(*types)->name, strlen((*types)->name)))
return (enum db_type) (*types)->db_type;
}
@@ -203,15 +206,21 @@ retest:
*/
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
{
- if (!my_strcasecmp(&my_charset_latin1, ptr, table_alias->alias))
+ if (!my_strnncoll(&my_charset_latin1,
+ (const uchar *)name, namelen,
+ (const uchar *)table_alias->alias,
+ strlen(table_alias->alias)))
{
- ptr= table_alias->type;
+ name= table_alias->type;
+ namelen= strlen(name);
goto retest;
}
}
return DB_TYPE_UNKNOWN;
}
+
+
const char *ha_get_storage_engine(enum db_type db_type)
{
handlerton **types;
@@ -220,25 +229,19 @@ const char *ha_get_storage_engine(enum db_type db_type)
if (db_type == (*types)->db_type)
return (*types)->name;
}
-
- return "none";
+ return "*NONE*";
}
+
bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag)
{
handlerton **types;
for (types= sys_table_types; *types; types++)
{
if (db_type == (*types)->db_type)
- {
- if ((*types)->flags & flag)
- return TRUE;
- else
- return FALSE;
- }
+ return test((*types)->flags & flag);
}
-
- return FALSE;
+ return FALSE; // No matching engine
}
@@ -299,26 +302,26 @@ enum db_type ha_checktype(THD *thd, enum db_type database_type,
} /* ha_checktype */
-handler *get_new_handler(TABLE *table, enum db_type db_type)
+handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
{
handler *file;
switch (db_type) {
#ifndef NO_HASH
case DB_TYPE_HASH:
- file= new ha_hash(table);
+ file= new (alloc) ha_hash(table);
break;
#endif
case DB_TYPE_MRG_ISAM:
- file= new ha_myisammrg(table);
+ file= new (alloc) ha_myisammrg(table);
break;
#ifdef HAVE_BERKELEY_DB
case DB_TYPE_BERKELEY_DB:
- file= new ha_berkeley(table);
+ file= new (alloc) ha_berkeley(table);
break;
#endif
#ifdef HAVE_INNOBASE_DB
case DB_TYPE_INNODB:
- file= new ha_innobase(table);
+ file= new (alloc) ha_innobase(table);
break;
#endif
#ifdef HAVE_EXAMPLE_DB
@@ -329,51 +332,51 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
#ifdef HAVE_PARTITION_DB
case DB_TYPE_PARTITION_DB:
{
- file= new ha_partition(table);
+ file= new (alloc) ha_partition(table);
break;
}
#endif
#ifdef HAVE_ARCHIVE_DB
case DB_TYPE_ARCHIVE_DB:
- file= new ha_archive(table);
+ file= new (alloc) ha_archive(table);
break;
#endif
#ifdef HAVE_BLACKHOLE_DB
case DB_TYPE_BLACKHOLE_DB:
- file= new ha_blackhole(table);
+ file= new (alloc) ha_blackhole(table);
break;
#endif
#ifdef HAVE_FEDERATED_DB
case DB_TYPE_FEDERATED_DB:
- file= new ha_federated(table);
+ file= new (alloc) ha_federated(table);
break;
#endif
#ifdef HAVE_CSV_DB
case DB_TYPE_CSV_DB:
- file= new ha_tina(table);
+ file= new (alloc) ha_tina(table);
break;
#endif
#ifdef HAVE_NDBCLUSTER_DB
case DB_TYPE_NDBCLUSTER:
- file= new ha_ndbcluster(table);
+ file= new (alloc) ha_ndbcluster(table);
break;
#endif
case DB_TYPE_HEAP:
- file= new ha_heap(table);
+ file= new (alloc) ha_heap(table);
break;
default: // should never happen
{
enum db_type def=(enum db_type) current_thd->variables.table_type;
/* Try first with 'default table type' */
if (db_type != def)
- return get_new_handler(table, def);
+ return get_new_handler(table, alloc, def);
}
/* Fall back to MyISAM */
case DB_TYPE_MYISAM:
- file= new ha_myisam(table);
+ file= new (alloc) ha_myisam(table);
break;
case DB_TYPE_MRG_MYISAM:
- file= new ha_myisammrg(table);
+ file= new (alloc) ha_myisammrg(table);
break;
}
if (file)
@@ -383,8 +386,6 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
delete file;
file=0;
}
- }
- return file;
}
@@ -912,18 +913,25 @@ int ha_autocommit_or_rollback(THD *thd, int error)
DBUG_RETURN(error);
}
+
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
{
handlerton **types;
int res= 1;
for (types= sys_table_types; *types; types++)
+ {
if ((*types)->state == SHOW_OPTION_YES && (*types)->recover)
- res= res &&
- (*(commit ? (*types)->commit_by_xid : (*types)->rollback_by_xid))(xid);
+ {
+ if ((*(commit ? (*types)->commit_by_xid :
+ (*types)->rollback_by_xid))(xid));
+ res= 0;
+ }
+ }
return res;
}
+
#ifndef DBUG_OFF
/* this does not need to be multi-byte safe or anything */
static char* xid_to_str(char *buf, XID *xid)
@@ -1352,7 +1360,7 @@ int ha_delete_table(THD *thd, enum db_type table_type, const char *path,
/* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
if (table_type == DB_TYPE_UNKNOWN ||
- ! (file=get_new_handler(&dummy_table, table_type)))
+ ! (file=get_new_handler(&dummy_table, thd->mem_root, table_type)))
DBUG_RETURN(ENOENT);
if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
@@ -2173,7 +2181,7 @@ int ha_create_table_from_engine(THD* thd,
DBUG_RETURN(3);
update_create_info_from_table(&create_info, &table);
- create_info.table_options|= HA_CREATE_FROM_ENGINE;
+ create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
if (lower_case_table_names == 2 &&
!(table.file->table_flags() & HA_FILE_BASED))
@@ -2626,6 +2634,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key,
TYPELIB *ha_known_exts(void)
{
+ MEM_ROOT *mem_root= current_thd->mem_root;
if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
{
handlerton **types;
@@ -2640,7 +2649,8 @@ TYPELIB *ha_known_exts(void)
{
if ((*types)->state == SHOW_OPTION_YES)
{
- handler *file= get_new_handler(0,(enum db_type) (*types)->db_type);
+ handler *file= get_new_handler(0, mem_root,
+ (enum db_type) (*types)->db_type);
for (ext= file->bas_ext(); *ext; ext++)
{
while ((old_ext= it++))
diff --git a/sql/handler.h b/sql/handler.h
index 2347c03ae2d..8d749c5fc33 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -664,6 +664,7 @@ typedef struct st_ha_create_information
uint options; /* OR of HA_CREATE_ options */
uint raid_type,raid_chunks;
uint merge_insert_method;
+ uint extra_size; /* length of extra data segment */
bool table_existed; /* 1 in create if table existed */
bool frm_only; /* 1 if no ha_create_table() */
bool varchar; /* 1 if table has a VARCHAR */
@@ -1389,7 +1390,7 @@ extern ulong total_ha, total_ha_2pc;
/* lookups */
enum db_type ha_resolve_by_name(const char *name, uint namelen);
const char *ha_get_storage_engine(enum db_type db_type);
-handler *get_new_handler(TABLE *table, enum db_type db_type);
+handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type);
enum db_type ha_checktype(THD *thd, enum db_type database_type,
bool no_substitute, bool report_error);
bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag);
diff --git a/sql/item.cc b/sql/item.cc
index 5caac05f6ca..9a64b02f80b 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -696,6 +696,32 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
}
+Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ if (const_item())
+ {
+ Item_string *conv;
+ uint cnv_errors;
+ char buf[MAX_FIELD_WIDTH];
+ String tmp(buf, sizeof(buf), &my_charset_bin);
+ String cstr, *ostr= val_str(&tmp);
+ /*
+ As safe_charset_converter is not executed for
+ a parameter bound to NULL, ostr should never be 0.
+ */
+ cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &cnv_errors);
+ if (cnv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
+ return NULL;
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ return conv;
+ }
+ return NULL;
+}
+
+
Item *Item_static_string_func::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
@@ -729,7 +755,8 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
{
if (binary_cmp)
return !stringcmp(&str_value, &item->str_value);
- return !sortcmp(&str_value, &item->str_value, collation.collation);
+ return (collation.collation == item->collation.collation &&
+ !sortcmp(&str_value, &item->str_value, collation.collation));
}
return 0;
}
@@ -817,9 +844,12 @@ String *Item_splocal::val_str(String *sp)
{
DBUG_ASSERT(fixed);
Item *it= this_item();
- String *ret= it->val_str(sp);
+ String *res= it->val_str(sp);
null_value= it->null_value;
+ if (!res)
+ return NULL;
+
/*
This way we mark returned value of val_str as const,
so that various functions (e.g. CONCAT) won't try to
@@ -836,12 +866,11 @@ String *Item_splocal::val_str(String *sp)
Item_param class contain some more details on the topic.
*/
- if (!ret)
- return NULL;
-
- str_value_ptr.set(ret->ptr(), ret->length(),
- ret->charset());
- return &str_value_ptr;
+ if (res != &str_value)
+ str_value.set(res->ptr(), res->length(), res->charset());
+ else
+ res->mark_as_const();
+ return &str_value;
}
@@ -858,17 +887,13 @@ my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
bool Item_splocal::is_null()
{
Item *it= this_item();
- bool ret= it->is_null();
- null_value= it->null_value;
- return ret;
+ return it->is_null();
}
Item *
Item_splocal::this_item()
{
- THD *thd= current_thd;
-
return thd->spcont->get_item(m_offset);
}
@@ -882,25 +907,23 @@ Item_splocal::this_item_addr(THD *thd, Item **addr)
Item *
Item_splocal::this_const_item() const
{
- THD *thd= current_thd;
-
return thd->spcont->get_item(m_offset);
}
Item::Type
Item_splocal::type() const
{
- THD *thd= current_thd;
-
- if (thd->spcont)
+ if (thd && thd->spcont)
return thd->spcont->get_item(m_offset)->type();
return NULL_ITEM; // Anything but SUBSELECT_ITEM
}
-bool Item_splocal::fix_fields(THD *, Item **)
+bool Item_splocal::fix_fields(THD *thd_arg, Item **ref)
{
- Item *it= this_item();
+ Item *it;
+ thd= thd_arg; // Must be set before this_item()
+ it= this_item();
DBUG_ASSERT(it->fixed);
max_length= it->max_length;
decimals= it->decimals;
@@ -928,6 +951,7 @@ void Item_splocal::print(String *str)
/*****************************************************************************
Item_name_const methods
*****************************************************************************/
+
double Item_name_const::val_real()
{
DBUG_ASSERT(fixed);
@@ -966,9 +990,7 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value)
bool Item_name_const::is_null()
{
- bool ret= value_item->is_null();
- null_value= value_item->null_value;
- return ret;
+ return value_item->is_null();
}
Item::Type Item_name_const::type() const
@@ -977,7 +999,7 @@ Item::Type Item_name_const::type() const
}
-bool Item_name_const::fix_fields(THD *thd, Item **)
+bool Item_name_const::fix_fields(THD *thd, Item **ref)
{
char buf[128];
String *item_name;
@@ -1356,7 +1378,7 @@ bool agg_item_charsets(DTCollation &coll, const char *fname,
been created in prepare. In this case register the change for
rollback.
*/
- if (arena)
+ if (arena && arena->is_conventional())
*arg= conv;
else
thd->change_item_tree(arg, conv);
@@ -2783,7 +2805,7 @@ int Item_copy_string::save_in_field(Field *field, bool no_conversions)
*/
/* ARGSUSED */
-bool Item::fix_fields(THD *thd, Item ** ref)
+bool Item::fix_fields(THD *thd, Item **ref)
{
// We do not check fields which are fixed during construction
@@ -3213,11 +3235,26 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
context->last_name_resolution_table,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
- !any_privileges &&
- context->check_privileges,
+ !any_privileges,
TRUE)) ==
not_found_field)
{
+
+ /* Look up in current select's item_list to find aliased fields */
+ if (thd->lex->current_select->is_item_list_lookup)
+ {
+ uint counter;
+ bool not_used;
+ Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
+ &counter, REPORT_EXCEPT_NOT_FOUND,
+ &not_used);
+ if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM)
+ {
+ set_field((*((Item_field**)res))->field);
+ return 0;
+ }
+ }
+
/*
If there are outer contexts (outer selects, but current select is
not derived table or view) try to resolve this reference in the
@@ -3260,9 +3297,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
last_name_resolution_table,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
- outer_context->
- check_privileges,
- TRUE)) !=
+ TRUE, TRUE)) !=
not_found_field)
{
if (from_field)
@@ -3337,7 +3372,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
context->last_name_resolution_table,
reference, REPORT_ALL_ERRORS,
!any_privileges &&
- context->check_privileges, TRUE);
+ TRUE, TRUE);
}
goto error;
}
@@ -3412,7 +3447,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
We can leave expression substituted from view for next PS/SP rexecution
(i.e. do not register this substitution for reverting on cleupup()
(register_item_tree_changing())), because this subtree will be
- fix_field'ed during setup_tables()->setup_ancestor() (i.e. before
+ fix_field'ed during setup_tables()->setup_underlying() (i.e. before
all other expressions of query, and references on tables which do
not present in query will not make problems.
@@ -4512,8 +4547,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
last_name_resolution_table,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
- outer_context->check_privileges,
- TRUE);
+ TRUE, TRUE);
if (! from_field)
goto error;
if (from_field == view_ref_found)
@@ -4638,7 +4672,7 @@ void Item_ref::cleanup()
void Item_ref::print(String *str)
{
- if (ref && *ref)
+ if (ref)
(*ref)->print(str);
else
Item_ident::print(str);
@@ -4770,8 +4804,7 @@ String *Item_ref::val_str(String* tmp)
bool Item_ref::is_null()
{
DBUG_ASSERT(fixed);
- (void) (*ref)->val_int_result();
- return (*ref)->null_value;
+ return (*ref)->is_null();
}
@@ -4825,7 +4858,7 @@ void Item_ref::make_field(Send_field *field)
void Item_ref_null_helper::print(String *str)
{
str->append("<ref_null_helper>(", 18);
- if (ref && *ref)
+ if (ref)
(*ref)->print(str);
else
str->append('?');
@@ -5053,8 +5086,17 @@ bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
bool Item_insert_value::fix_fields(THD *thd, Item **items)
{
DBUG_ASSERT(fixed == 0);
- if (!arg->fixed && arg->fix_fields(thd, &arg))
- return TRUE;
+ /* We should only check that arg is in first table */
+ if (!arg->fixed)
+ {
+ bool res;
+ st_table_list *orig_next_table= context->last_name_resolution_table;
+ context->last_name_resolution_table= context->first_name_resolution_table;
+ res= arg->fix_fields(thd, &arg);
+ context->last_name_resolution_table= orig_next_table;
+ if (res)
+ return TRUE;
+ }
if (arg->type() == REF_ITEM)
{
@@ -5066,6 +5108,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
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());
@@ -5126,7 +5169,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
set field_idx properly.
*/
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
- 0, 0, &field_idx);
+ 0, 0, &field_idx, 0);
thd->set_query_id= save_set_query_id;
triggers= table->triggers;
}
@@ -5241,32 +5284,21 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
}
case ROW_RESULT:
{
+ Item_row *item_row= (Item_row*) item;
+ Item_row *comp_item_row= (Item_row*) comp_item;
+ uint col;
new_item= 0;
/*
If item and comp_item are both Item_rows and have same number of cols
- then process items in Item_row one by one. If Item_row contain nulls
- substitute it by Item_null. Otherwise just return.
+ then process items in Item_row one by one.
+ We can't ignore NULL values here as this item may be used with <=>, in
+ which case NULL's are significant.
*/
- if (item->result_type() == comp_item->result_type() &&
- ((Item_row*)item)->cols() == ((Item_row*)comp_item)->cols())
- {
- Item_row *item_row= (Item_row*)item,*comp_item_row= (Item_row*)comp_item;
- if (item_row->null_inside())
- new_item= (Item*) new Item_null(name);
- else
- {
- int i= item_row->cols() - 1;
- for (; i >= 0; i--)
- {
- if (item_row->maybe_null && item_row->el(i)->is_null())
- {
- new_item= (Item*) new Item_null(name);
- break;
- }
- resolve_const_item(thd, item_row->addr(i), comp_item_row->el(i));
- }
- }
- }
+ DBUG_ASSERT(item->result_type() == comp_item->result_type());
+ DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
+ col= item_row->cols();
+ while (col-- > 0)
+ resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col));
break;
}
case REAL_RESULT:
@@ -5721,6 +5753,8 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
bool Item_type_holder::join_types(THD *thd, Item *item)
{
+ uint max_length_orig= max_length;
+ uint decimals_orig= decimals;
DBUG_ENTER("Item_type_holder::join_types");
DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s",
fld_type, max_length, decimals,
@@ -5747,7 +5781,10 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
}
else
max_length= max(max_length, display_length(item));
- if (Field::result_merge_type(fld_type) == STRING_RESULT)
+
+ switch (Field::result_merge_type(fld_type))
+ {
+ case STRING_RESULT:
{
const char *old_cs, *old_derivation;
old_cs= collation.collation->name;
@@ -5761,7 +5798,23 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
"UNION");
DBUG_RETURN(TRUE);
}
+ break;
+ }
+ case REAL_RESULT:
+ {
+ if (decimals != NOT_FIXED_DEC)
+ {
+ int delta1= max_length_orig - decimals_orig;
+ int delta2= item->max_length - item->decimals;
+ max_length= min(max(delta1, delta2) + decimals,
+ (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7);
+ }
+ else
+ max_length= (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7;
+ break;
}
+ default:;
+ };
maybe_null|= item->maybe_null;
get_full_info(item);
diff --git a/sql/item.h b/sql/item.h
index a8f013f60d4..8bc659c3060 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -294,15 +294,15 @@ struct Name_resolution_context: Sql_alloc
bool resolve_in_select_list;
/*
- When FALSE we do not check columns right of resolving items, used to
- prevent rights check on underlying tables of view
+ Security context of this name resolution context. It's used for views
+ and is non-zero only if the view is defined with SQL SECURITY DEFINER.
*/
- bool check_privileges;
+ Security_context *security_ctx;
Name_resolution_context()
:outer_context(0), table_list(0), select_lex(0),
error_processor_data(0),
- check_privileges(TRUE)
+ security_ctx(0)
{}
void init()
@@ -526,6 +526,7 @@ public:
double val_real_from_decimal();
virtual Field *get_tmp_table_field() { return 0; }
+ /* This is also used to create fields in CREATE ... SELECT: */
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
@@ -721,13 +722,7 @@ class Item_splocal : public Item
public:
LEX_STRING m_name;
-
- /*
- Buffer, pointing to the string value of the item. We need it to
- protect internal buffer from changes. See comment to analogous
- member in Item_param for more details.
- */
- String str_value_ptr;
+ THD *thd;
/*
Position of this reference to SP variable in the statement (the
@@ -739,10 +734,10 @@ public:
Value of 0 means that this object doesn't corresponding to reference to
SP variable in query text.
*/
- int pos_in_query;
+ uint pos_in_query;
- Item_splocal(LEX_STRING name, uint offset, int pos_in_q=0)
- : m_offset(offset), m_name(name), pos_in_query(pos_in_q)
+ Item_splocal(LEX_STRING name, uint offset, uint pos_in_q=0)
+ : m_offset(offset), m_name(name), thd(0), pos_in_query(pos_in_q)
{
maybe_null= TRUE;
}
@@ -1200,6 +1195,7 @@ public:
constant, assert otherwise. This method is called only if
basic_const_item returned TRUE.
*/
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
Item *new_item();
/*
Implement by-value equality evaluation if parameter value
@@ -1337,6 +1333,14 @@ public:
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
+ if (value <= (double) LONGLONG_MIN)
+ {
+ return LONGLONG_MIN;
+ }
+ else if (value >= (double) (ulonglong) LONGLONG_MAX)
+ {
+ return LONGLONG_MAX;
+ }
return (longlong) (value+(value > 0 ? 0.5 : -0.5));
}
String *val_str(String*);
@@ -1622,7 +1626,7 @@ public:
}
Item *real_item()
{
- return (ref && *ref) ? (*ref)->real_item() : this;
+ return ref ? (*ref)->real_item() : this;
}
bool walk(Item_processor processor, byte *arg)
{ return (*ref)->walk(processor, arg); }
@@ -1746,6 +1750,7 @@ public:
return ref->save_in_field(field, no_conversions);
}
Item *new_item();
+ virtual Item *real_item() { return ref; }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 138ebaaf9a5..06cb83a7101 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -186,13 +186,18 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
{
if ((*item)->const_item())
{
+ /* For comparison purposes allow invalid dates like 2000-01-32 */
+ ulong orig_sql_mode= field->table->in_use->variables.sql_mode;
+ field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
Item *tmp=new Item_int_with_ref(field->val_int(), *item);
+ field->table->in_use->variables.sql_mode= orig_sql_mode;
if (tmp)
thd->change_item_tree(item, tmp);
return 1; // Item was replaced
}
+ field->table->in_use->variables.sql_mode= orig_sql_mode;
}
return 0;
}
@@ -2958,6 +2963,15 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
String *escape_str= escape_item->val_str(&tmp_value1);
if (escape_str)
{
+ if (escape_used_in_parsing && (
+ (((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
+ escape_str->numchars() != 1) ||
+ escape_str->numchars() > 1)))
+ {
+ my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE");
+ return TRUE;
+ }
+
if (use_mb(cmp.cmp_collation.collation))
{
CHARSET_INFO *cs= escape_str->charset();
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index aa50593abf4..bfd32223d4c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -985,13 +985,16 @@ class Item_func_like :public Item_bool_func2
enum { alphabet_size = 256 };
Item *escape_item;
+
+ bool escape_used_in_parsing;
public:
int escape;
- Item_func_like(Item *a,Item *b, Item *escape_arg)
+ Item_func_like(Item *a,Item *b, Item *escape_arg, bool escape_used)
:Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0),
- bmGs(0), bmBc(0), escape_item(escape_arg) {}
+ bmGs(0), bmBc(0), escape_item(escape_arg),
+ escape_used_in_parsing(escape_used) {}
longlong val_int();
enum Functype functype() const { return LIKE_FUNC; }
optimize_type select_optimize() const;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index f07460f2a05..f467981540b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -32,6 +32,11 @@
#include "sp_rcontext.h"
#include "sp.h"
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+#define sp_restore_security_context(A,B) while (0) {}
+#endif
+
+
bool check_reserved_words(LEX_STRING *name)
{
if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") ||
@@ -967,8 +972,8 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 1)))
+ (my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 3))))
return decimal_value;
return 0;
}
@@ -1040,8 +1045,8 @@ my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 1)))
+ (my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 3))))
return decimal_value;
return 0;
}
@@ -1078,8 +1083,8 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 1)))
+ (my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 3))))
return decimal_value;
return 0;
}
@@ -1119,6 +1124,7 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
my_decimal value1, *val1;
my_decimal value2, *val2;
+ int err;
val1= args[0]->val_decimal(&value1);
if ((null_value= args[0]->null_value))
@@ -1126,17 +1132,15 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value))
return 0;
- switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
- val1, val2, prec_increment)) {
- case E_DEC_TRUNCATED:
- case E_DEC_OK:
- return decimal_value;
- case E_DEC_DIV_ZERO:
- signal_divide_by_null();
- default:
- null_value= 1; // Safety
+ if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
+ val1, val2, prec_increment)) > 3)
+ {
+ if (err == E_DEC_DIV_ZERO)
+ signal_divide_by_null();
+ null_value= 1;
return 0;
}
+ return decimal_value;
}
@@ -1381,8 +1385,13 @@ double Item_func_ln::val_real()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- if ((null_value=(args[0]->null_value || value <= 0.0)))
+ if ((null_value= args[0]->null_value))
+ return 0.0;
+ if (value <= 0.0)
+ {
+ signal_divide_by_null();
return 0.0;
+ }
return log(value);
}
@@ -1395,13 +1404,23 @@ double Item_func_log::val_real()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- if ((null_value=(args[0]->null_value || value <= 0.0)))
+ if ((null_value= args[0]->null_value))
return 0.0;
+ if (value <= 0.0)
+ {
+ signal_divide_by_null();
+ return 0.0;
+ }
if (arg_count == 2)
{
double value2= args[1]->val_real();
- if ((null_value=(args[1]->null_value || value2 <= 0.0 || value == 1.0)))
+ if ((null_value= args[1]->null_value))
+ return 0.0;
+ if (value2 <= 0.0 || value == 1.0)
+ {
+ signal_divide_by_null();
return 0.0;
+ }
return log(value2) / log(value);
}
return log(value);
@@ -1411,8 +1430,14 @@ double Item_func_log2::val_real()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- if ((null_value=(args[0]->null_value || value <= 0.0)))
+
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ if (value <= 0.0)
+ {
+ signal_divide_by_null();
return 0.0;
+ }
return log(value) / M_LN2;
}
@@ -1420,8 +1445,13 @@ double Item_func_log10::val_real()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- if ((null_value=(args[0]->null_value || value <= 0.0)))
- return 0.0; /* purecov: inspected */
+ if ((null_value= args[0]->null_value))
+ return 0.0;
+ if (value <= 0.0)
+ {
+ signal_divide_by_null();
+ return 0.0;
+ }
return log10(value);
}
@@ -2015,7 +2045,6 @@ String *Item_func_min_max::val_str(String *str)
{
String *res;
LINT_INIT(res);
- null_value= 0;
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
@@ -2030,14 +2059,11 @@ String *Item_func_min_max::val_str(String *str)
if ((cmp_sign < 0 ? cmp : -cmp) < 0)
res=res2;
}
- else
- res= 0;
}
if ((null_value= args[i]->null_value))
- break;
+ return 0;
}
- if (res) // If !NULL
- res->set_charset(collation.collation);
+ res->set_charset(collation.collation);
return res;
}
case ROW_RESULT:
@@ -2054,7 +2080,6 @@ double Item_func_min_max::val_real()
{
DBUG_ASSERT(fixed == 1);
double value=0.0;
- null_value= 0;
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
@@ -2076,7 +2101,6 @@ longlong Item_func_min_max::val_int()
{
DBUG_ASSERT(fixed == 1);
longlong value=0;
- null_value= 0;
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
@@ -2097,21 +2121,21 @@ longlong Item_func_min_max::val_int()
my_decimal *Item_func_min_max::val_decimal(my_decimal *dec)
{
DBUG_ASSERT(fixed == 1);
- my_decimal tmp_buf, *tmp, *res= NULL;
- null_value= 0;
+ my_decimal tmp_buf, *tmp, *res;
+ LINT_INIT(res);
+
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
res= args[i]->val_decimal(dec);
else
{
- tmp= args[i]->val_decimal(&tmp_buf);
- if (args[i]->null_value)
- res= 0;
- else if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0)
+ tmp= args[i]->val_decimal(&tmp_buf); // Zero if NULL
+ if (tmp && (my_decimal_cmp(tmp, res) * cmp_sign) < 0)
{
if (tmp == &tmp_buf)
{
+ /* Move value out of tmp_buf as this will be reused on next loop */
my_decimal2decimal(tmp, dec);
res= dec;
}
@@ -2120,7 +2144,10 @@ my_decimal *Item_func_min_max::val_decimal(my_decimal *dec)
}
}
if ((null_value= args[i]->null_value))
+ {
+ res= 0;
break;
+ }
}
return res;
}
@@ -2349,7 +2376,7 @@ void Item_func_find_in_set::fix_length_and_dec()
}
}
}
- agg_arg_collations_for_comparison(cmp_collation, args, 2);
+ agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV);
}
static const char separator=',';
@@ -3031,9 +3058,13 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
thd->mysys_var->current_cond= &ull->cond;
set_timespec(abstime,lock_timeout);
- while (!thd->killed &&
- pthread_cond_timedwait(&ull->cond, &LOCK_user_locks,
- &abstime) != ETIMEDOUT && ull->locked) ;
+ while (ull->locked && !thd->killed)
+ {
+ int error= pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, &abstime);
+ if (error == ETIMEDOUT || error == ETIME)
+ break;
+ }
+
if (ull->locked)
{
if (!--ull->count)
@@ -3077,7 +3108,7 @@ longlong Item_func_get_lock::val_int()
struct timespec abstime;
THD *thd=current_thd;
User_level_lock *ull;
- int error=0;
+ int error;
/*
In slave thread no need to get locks, everything is serialized. Anyway
@@ -3133,22 +3164,29 @@ longlong Item_func_get_lock::val_int()
thd->mysys_var->current_cond= &ull->cond;
set_timespec(abstime,timeout);
- while (!thd->killed &&
- (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
- != ETIMEDOUT && error != EINVAL && ull->locked) ;
- if (thd->killed)
- error=EINTR; // Return NULL
+ error= 0;
+ while (ull->locked && !thd->killed)
+ {
+ error= pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime);
+ if (error == ETIMEDOUT || error == ETIME)
+ break;
+ error= 0;
+ }
+
if (ull->locked)
{
if (!--ull->count)
+ {
+ DBUG_ASSERT(0);
delete ull; // Should never happen
- if (error != ETIMEDOUT)
+ }
+ if (!error) // Killed (thd->killed != 0)
{
error=1;
null_value=1; // Return NULL
}
}
- else
+ else // We got the lock
{
ull->locked=1;
ull->thread=thd->real_id;
@@ -3270,6 +3308,7 @@ void Item_func_benchmark::print(String *str)
str->append(')');
}
+
/* This function is just used to create tests with time gaps */
longlong Item_func_sleep::val_int()
@@ -3290,10 +3329,14 @@ longlong Item_func_sleep::val_int()
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &cond;
- while (!thd->killed &&
- (error= pthread_cond_timedwait(&cond, &LOCK_user_locks,
- &abstime)) != ETIMEDOUT &&
- error != EINVAL) ;
+ error= 0;
+ while (!thd->killed)
+ {
+ error= pthread_cond_timedwait(&cond, &LOCK_user_locks, &abstime);
+ if (error == ETIMEDOUT || error == ETIME)
+ break;
+ error= 0;
+ }
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
@@ -3303,7 +3346,7 @@ longlong Item_func_sleep::val_int()
pthread_mutex_unlock(&LOCK_user_locks);
pthread_cond_destroy(&cond);
- return (error == ETIMEDOUT) ? 0 : 1;
+ return test(!error); // Return 1 killed
}
@@ -4485,7 +4528,6 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component)
{
sys_var *var;
- char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
LEX_STRING *base_name, *component_name;
if (component.str == 0 &&
@@ -4689,6 +4731,7 @@ Item_func_sp::execute(Field **flp)
if (execute(&it))
{
null_value= 1;
+ context->process_error(current_thd);
return 1;
}
if (!(f= *flp))
@@ -4711,9 +4754,16 @@ Item_func_sp::execute(Item **itp)
THD *thd= current_thd;
int res= -1;
Sub_statement_state statement_state;
- Security_context *save_ctx;
+ Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
- if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (context->security_ctx)
+ {
+ /* Set view definer security context */
+ thd->security_ctx= context->security_ctx;
+ }
+#endif
+ if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx_func))
goto error;
/*
@@ -4731,12 +4781,13 @@ Item_func_sp::execute(Item **itp)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_FAILED_ROUTINE_BREAK_BINLOG,
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
-
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sp_restore_security_context(thd, save_ctx);
-#endif
-
+ sp_restore_security_context(thd, save_ctx_func);
error:
+ thd->security_ctx= save_security_ctx;
+#else
+error:
+#endif
DBUG_RETURN(res);
}
@@ -4849,11 +4900,12 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
find_and_check_access()
thd thread handler
want_access requested access
- backup backup of security context or 0
+ save backup of security context
RETURN
FALSE Access granted
TRUE Requested access can't be granted or function doesn't exists
+ In this case security context is not changed and *save = 0
NOTES
Checks if requested access to function can be granted to user.
@@ -4868,12 +4920,11 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
bool
Item_func_sp::find_and_check_access(THD *thd, ulong want_access,
- Security_context **backup)
+ Security_context **save)
{
- bool res;
- Security_context *local_save,
- **save= (backup ? backup : &local_save);
- res= TRUE;
+ bool res= TRUE;
+
+ *save= 0; // Safety if error
if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE)))
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
@@ -4883,26 +4934,31 @@ Item_func_sp::find_and_check_access(THD *thd, ulong want_access,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, want_access,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
- {
goto error;
- }
sp_change_security_context(thd, m_sp, save);
+ /*
+ If we changed context to run as another user, we need to check the
+ access right for the new context again as someone may have deleted
+ this person the right to use the procedure
+
+ TODO:
+ Cache if the definer has the right to use the object on the first
+ usage and only reset the cache if someone does a GRANT statement
+ that 'may' affect this.
+ */
if (*save &&
check_routine_access(thd, want_access,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
{
- goto error_check_ctx;
+ sp_restore_security_context(thd, *save);
+ *save= 0; // Safety
+ goto error;
}
- res= FALSE;
-error_check_ctx:
- if (*save && (res || !backup))
- sp_restore_security_context(thd, local_save);
-error:
-#else
- res= 0;
-error:
#endif
+ res= FALSE; // no error
+
+error:
return res;
}
@@ -4912,7 +4968,23 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
bool res;
DBUG_ASSERT(fixed == 0);
res= Item_func::fix_fields(thd, ref);
- if (!res && find_and_check_access(thd, EXECUTE_ACL, NULL))
- res= 1;
+ if (!res && thd->lex->view_prepare_mode)
+ {
+ /*
+ Here we check privileges of the stored routine only during view
+ creation, in order to validate the view. A runtime check is perfomed
+ in Item_func_sp::execute(), and this method is not called during
+ context analysis. We do not need to restore the security context
+ changed in find_and_check_access because all view structures created
+ in CREATE VIEW are not used for execution. Notice, that during view
+ creation we do not infer into stored routine bodies and do not check
+ privileges of its statements, which would probably be a good idea
+ especially if the view has SQL SECURITY DEFINER and the used stored
+ procedure has SQL SECURITY DEFINER
+ */
+ Security_context *save_ctx;
+ if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
+ sp_restore_security_context(thd, save_ctx);
+ }
return res;
}
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 4a6ceb4bf7d..2b92e72e728 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -81,8 +81,7 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
str->q_append(srid);
if ((null_value=
(args[0]->null_value ||
- !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length()) ||
- str->append(*wkb))))
+ !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str))))
return 0;
return str;
}
@@ -99,8 +98,7 @@ String *Item_func_as_wkt::val_str(String *str)
if ((null_value=
(args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)))))
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0;
str->length(0);
@@ -126,8 +124,7 @@ String *Item_func_as_wkb::val_str(String *str)
if ((null_value=
(args[0]->null_value ||
- !(Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)))))
+ !(Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0;
str->copy(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE,
@@ -145,8 +142,7 @@ String *Item_func_geometry_type::val_str(String *str)
if ((null_value=
(args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)))))
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0;
/* String will not move */
str->copy(geom->get_class_info()->m_name.str,
@@ -167,8 +163,7 @@ String *Item_func_envelope::val_str(String *str)
if ((null_value=
args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE))))
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
return 0;
srid= uint4korr(swkb->ptr());
@@ -191,8 +186,7 @@ String *Item_func_centroid::val_str(String *str)
uint32 srid;
if ((null_value= args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE))))
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
return 0;
str->set_charset(&my_charset_bin);
@@ -221,8 +215,7 @@ String *Item_func_spatial_decomp::val_str(String *str)
if ((null_value=
(args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)))))
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0;
srid= uint4korr(swkb->ptr());
@@ -270,8 +263,7 @@ String *Item_func_spatial_decomp_n::val_str(String *str)
if ((null_value=
(args[0]->null_value || args[1]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)))))
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0;
str->set_charset(&my_charset_bin);
@@ -478,10 +470,8 @@ longlong Item_func_spatial_rel::val_int()
if ((null_value=
(args[0]->null_value ||
args[1]->null_value ||
- !(g1= Geometry::create_from_wkb(&buffer1, res1->ptr() + SRID_SIZE,
- res1->length() - SRID_SIZE)) ||
- !(g2= Geometry::create_from_wkb(&buffer2, res2->ptr() + SRID_SIZE,
- res2->length() - SRID_SIZE)) ||
+ !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
+ !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) ||
g1->get_mbr(&mbr1, &dummy) ||
g2->get_mbr(&mbr2, &dummy))))
return 0;
@@ -546,8 +536,7 @@ longlong Item_func_isclosed::val_int()
null_value= (!swkb ||
args[0]->null_value ||
!(geom=
- Geometry::create_from_wkb(&buffer, swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
geom->is_closed(&isclosed));
return (longlong) isclosed;
@@ -569,9 +558,7 @@ longlong Item_func_dimension::val_int()
null_value= (!swkb ||
args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
geom->dimension(&dim, &dummy));
return (longlong) dim;
}
@@ -586,9 +573,8 @@ longlong Item_func_numinteriorring::val_int()
Geometry *geom;
null_value= (!swkb ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->num_interior_ring(&num));
return (longlong) num;
}
@@ -603,9 +589,8 @@ longlong Item_func_numgeometries::val_int()
Geometry *geom;
null_value= (!swkb ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->num_geometries(&num));
return (longlong) num;
}
@@ -621,9 +606,8 @@ longlong Item_func_numpoints::val_int()
null_value= (!swkb ||
args[0]->null_value ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->num_points(&num));
return (longlong) num;
}
@@ -638,9 +622,8 @@ double Item_func_x::val_real()
Geometry *geom;
null_value= (!swkb ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->get_x(&res));
return res;
}
@@ -655,9 +638,8 @@ double Item_func_y::val_real()
Geometry *geom;
null_value= (!swkb ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->get_y(&res));
return res;
}
@@ -673,9 +655,8 @@ double Item_func_area::val_real()
const char *dummy;
null_value= (!swkb ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->area(&res, &dummy));
return res;
}
@@ -689,9 +670,8 @@ double Item_func_glength::val_real()
Geometry *geom;
null_value= (!swkb ||
- !(geom= Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE)) ||
+ !(geom= Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length())) ||
geom->length(&res));
return res;
}
@@ -703,9 +683,8 @@ longlong Item_func_srid::val_int()
Geometry_buffer buffer;
null_value= (!swkb ||
- !Geometry::create_from_wkb(&buffer,
- swkb->ptr() + SRID_SIZE,
- swkb->length() - SRID_SIZE));
+ !Geometry::construct(&buffer,
+ swkb->ptr(), swkb->length()));
if (null_value)
return 0;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 018afac3812..1e8fe2e695f 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1504,7 +1504,13 @@ String *Item_func_encrypt::val_str(String *str)
salt_ptr= salt_str->c_ptr();
}
pthread_mutex_lock(&LOCK_crypt);
- char *tmp=crypt(res->c_ptr(),salt_ptr);
+ char *tmp= crypt(res->c_ptr(),salt_ptr);
+ if (!tmp)
+ {
+ pthread_mutex_unlock(&LOCK_crypt);
+ null_value= 1;
+ return 0;
+ }
str->set(tmp,(uint) strlen(tmp),res->charset());
str->copy();
pthread_mutex_unlock(&LOCK_crypt);
@@ -1964,21 +1970,16 @@ String *Item_func_char::val_str(String *str)
int32 num=(int32) args[i]->val_int();
if (!args[i]->null_value)
{
-#ifdef USE_MB
- if (use_mb(collation.collation))
- {
- if (num&0xFF000000L) {
- str->append((char)(num>>24));
- goto b2;
- } else if (num&0xFF0000L) {
-b2: str->append((char)(num>>16));
- goto b1;
- } else if (num&0xFF00L) {
-b1: str->append((char)(num>>8));
- }
+ if (num&0xFF000000L) {
+ str->append((char)(num>>24));
+ goto b2;
+ } else if (num&0xFF0000L) {
+ b2: str->append((char)(num>>16));
+ goto b1;
+ } else if (num&0xFF00L) {
+ b1: str->append((char)(num>>8));
}
-#endif
- str->append((char)num);
+ str->append((char) num);
}
}
str->set_charset(collation.collation);
@@ -1997,7 +1998,7 @@ b1: str->append((char)(num>>8));
enum MYSQL_ERROR::enum_warning_level level;
uint diff= str->length() - wlen;
set_if_smaller(diff, 3);
- octet2hex(hexbuf, (const uchar*) str->ptr() + wlen, diff);
+ octet2hex(hexbuf, str->ptr() + wlen, diff);
if (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
{
@@ -2436,6 +2437,7 @@ String *Item_func_collation::val_str(String *str)
String *Item_func_hex::val_str(String *str)
{
+ String *res;
DBUG_ASSERT(fixed == 1);
if (args[0]->result_type() != STRING_RESULT)
{
@@ -2464,24 +2466,16 @@ String *Item_func_hex::val_str(String *str)
}
/* Convert given string to a hex string, character by character */
- String *res= args[0]->val_str(str);
- const char *from, *end;
- char *to;
- if (!res || tmp_value.alloc(res->length()*2))
+ res= args[0]->val_str(str);
+ if (!res || tmp_value.alloc(res->length()*2+1))
{
null_value=1;
return 0;
}
null_value=0;
tmp_value.length(res->length()*2);
- for (from=res->ptr(), end=from+res->length(), to= (char*) tmp_value.ptr();
- from < end ;
- from++, to+=2)
- {
- uint tmp=(uint) (uchar) *from;
- to[0]=_dig_vec_upper[tmp >> 4];
- to[1]=_dig_vec_upper[tmp & 15];
- }
+
+ octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length());
return &tmp_value;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index fa098849a43..5889821293d 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -480,12 +480,15 @@ public:
class Item_func_char :public Item_str_func
{
public:
- Item_func_char(List<Item> &list) :Item_str_func(list) {}
+ Item_func_char(List<Item> &list) :Item_str_func(list)
+ { collation.set(&my_charset_bin); }
+ Item_func_char(List<Item> &list, CHARSET_INFO *cs) :Item_str_func(list)
+ { collation.set(cs); }
String *val_str(String *);
void fix_length_and_dec()
{
- collation.set(default_charset());
- maybe_null=0; max_length=arg_count;
+ maybe_null=0;
+ max_length=arg_count * collation.collation->mbmaxlen;
}
const char *func_name() const { return "char"; }
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 0e30bbd8a96..a32b0d1dbbf 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1413,6 +1413,12 @@ void subselect_union_engine::cleanup()
}
+bool subselect_union_engine::is_executed() const
+{
+ return unit->executed;
+}
+
+
void subselect_uniquesubquery_engine::cleanup()
{
DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 5b22930ae1f..f1c99f74498 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -110,6 +110,12 @@ public:
return eng == 0;
}
/*
+ True if this subquery has been already evaluated. Implemented only for
+ single select and union subqueries only.
+ */
+ bool is_evaluated() const;
+
+ /*
Used by max/min subquery to initialize value presence registration
mechanism. Engine call this method before rexecution query.
*/
@@ -317,6 +323,7 @@ public:
virtual void print(String *str)= 0;
virtual bool change_result(Item_subselect *si, select_subselect *result)= 0;
virtual bool no_tables()= 0;
+ virtual bool is_executed() const { return FALSE; }
};
@@ -342,6 +349,7 @@ public:
void print (String *str);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
+ bool is_executed() const { return executed; }
};
@@ -363,6 +371,7 @@ public:
void print (String *str);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
+ bool is_executed() const;
};
@@ -411,3 +420,10 @@ public:
int exec();
void print (String *str);
};
+
+
+inline bool Item_subselect::is_evaluated() const
+{
+ return engine->is_executed();
+}
+
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b56d99cf245..b2eaf39d624 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -3173,6 +3173,10 @@ void Item_func_group_concat::print(String *str)
if (i)
str->append(',');
(*order[i]->item)->print(str);
+ if (order[i]->asc)
+ str->append(" ASC");
+ else
+ str->append(" DESC");
}
}
str->append(" separator \'", 12);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 7f94c19647e..2b0314bb287 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1610,6 +1610,7 @@ void Item_func_date_format::fix_length_and_dec()
if (args[1]->type() == STRING_ITEM)
{ // Optimize the normal case
fixed_length=1;
+
/*
The result is a binary string (no reason to use collation->mbmaxlen
This is becasue make_date_time() only returns binary strings
@@ -1627,6 +1628,30 @@ void Item_func_date_format::fix_length_and_dec()
}
+bool Item_func_date_format::eq(const Item *item, bool binary_cmp) const
+{
+ Item_func_date_format *item_func;
+ if (item->type() != FUNC_ITEM)
+ return 0;
+ if (func_name() != ((Item_func*) item)->func_name())
+ return 0;
+ if (this == item)
+ return 1;
+ item_func= (Item_func_date_format*) item;
+ if (!args[0]->eq(item_func->args[0], binary_cmp))
+ return 0;
+ /*
+ We must compare format string case sensitive.
+ This needed because format modifiers with different case,
+ for example %m and %M, have different meaning.
+ */
+ if (!args[1]->eq(item_func->args[1], 1))
+ return 0;
+ return 1;
+}
+
+
+
uint Item_func_date_format::format_length(const String *format)
{
uint size=0;
@@ -2479,6 +2504,7 @@ void Item_func_add_time::fix_length_and_dec()
enum_field_types arg0_field_type;
decimals=0;
max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ maybe_null= 1;
/*
The field type for the result of an Item_func_add_time function is defined
@@ -2723,16 +2749,16 @@ longlong Item_func_timestamp_diff::val_int()
int_type == INTERVAL_QUARTER ||
int_type == INTERVAL_MONTH)
{
- uint year;
- uint year_beg, year_end, month_beg, month_end;
- uint diff_days= (uint) (seconds/86400L);
- uint diff_years= 0;
+ uint year_beg, year_end, month_beg, month_end, day_beg, day_end;
+ uint years= 0;
if (neg == -1)
{
year_beg= ltime2.year;
year_end= ltime1.year;
month_beg= ltime2.month;
month_end= ltime1.month;
+ day_beg= ltime2.day;
+ day_end= ltime1.day;
}
else
{
@@ -2740,53 +2766,32 @@ longlong Item_func_timestamp_diff::val_int()
year_end= ltime2.year;
month_beg= ltime1.month;
month_end= ltime2.month;
- }
- /* calc years*/
- for (year= year_beg;year < year_end; year++)
- {
- uint days=calc_days_in_year(year);
- if (days > diff_days)
- break;
- diff_days-= days;
- diff_years++;
+ day_beg= ltime1.day;
+ day_end= ltime2.day;
}
- /* calc months; Current year is in the 'year' variable */
- month_beg--; /* Change months to be 0-11 for easier calculation */
- month_end--;
+ /* calc years */
+ years= year_end - year_beg;
+ if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
+ years-= 1;
- months= 12*diff_years;
- while (month_beg != month_end)
- {
- uint m_days= (uint) days_in_month[month_beg];
- if (month_beg == 1)
- {
- /* This is only calculated once so there is no reason to cache it*/
- uint leap= (uint) ((year & 3) == 0 && (year%100 ||
- (year%400 == 0 && year)));
- m_days+= leap;
- }
- if (m_days > diff_days)
- break;
- diff_days-= m_days;
- months++;
- if (month_beg++ == 11) /* if we wrap to next year */
- {
- month_beg= 0;
- year++;
- }
- }
- if (neg == -1)
- months= -months;
+ /* calc months */
+ months= 12*years;
+ if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
+ months+= 12 - (month_beg - month_end);
+ else
+ months+= (month_end - month_beg);
+ if (day_end < day_beg)
+ months-= 1;
}
switch (int_type) {
case INTERVAL_YEAR:
- return months/12;
+ return months/12*neg;
case INTERVAL_QUARTER:
- return months/3;
+ return months/3*neg;
case INTERVAL_MONTH:
- return months;
+ return months*neg;
case INTERVAL_WEEK:
return seconds/86400L/7L*neg;
case INTERVAL_DAY:
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 8e15acbc1fc..b2352e728c5 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -537,6 +537,7 @@ public:
{ return is_time_format ? "time_format" : "date_format"; }
void fix_length_and_dec();
uint format_length(const String *format);
+ bool eq(const Item *item, bool binary_cmp) const;
};
@@ -844,6 +845,7 @@ public:
{
decimals=0;
max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ maybe_null= 1;
}
Field *tmp_table_field(TABLE *t_arg)
{
diff --git a/sql/log.cc b/sql/log.cc
index 0ab3e6f94ed..3341b0265eb 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -357,9 +357,10 @@ static int find_uniq_filename(char *name)
MYSQL_LOG::MYSQL_LOG()
:bytes_written(0), last_time(0), query_start(0), name(0),
- file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0),
- need_start_event(1), prepared_xids(0), description_event_for_exec(0),
- description_event_for_queue(0)
+ prepared_xids(0), log_type(LOG_CLOSED), file_id(1), open_count(1),
+ readers_count(0), reset_pending(FALSE), write_error(FALSE), inited(FALSE),
+ need_start_event(TRUE),
+ description_event_for_exec(0), description_event_for_queue(0)
{
/*
We don't want to initialize LOCK_Log here as such initialization depends on
@@ -385,7 +386,9 @@ void MYSQL_LOG::cleanup()
delete description_event_for_exec;
(void) pthread_mutex_destroy(&LOCK_log);
(void) pthread_mutex_destroy(&LOCK_index);
+ (void) pthread_mutex_destroy(&LOCK_readers);
(void) pthread_cond_destroy(&update_cond);
+ (void) pthread_cond_destroy(&reset_cond);
}
DBUG_VOID_RETURN;
}
@@ -430,7 +433,9 @@ void MYSQL_LOG::init_pthread_objects()
inited= 1;
(void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_readers, MY_MUTEX_INIT_SLOW);
(void) pthread_cond_init(&update_cond, 0);
+ (void) pthread_cond_init(&reset_cond, 0);
}
const char *MYSQL_LOG::generate_name(const char *log_name,
@@ -933,6 +938,13 @@ bool MYSQL_LOG::reset_logs(THD* thd)
*/
pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_index);
+
+ /*
+ we need one more lock to block attempts to open a log while
+ we are waiting untill all log files will be closed
+ */
+ pthread_mutex_lock(&LOCK_readers);
+
/*
The following mutex is needed to ensure that no threads call
'delete thd' as we would then risk missing a 'rollback' from this
@@ -955,6 +967,19 @@ bool MYSQL_LOG::reset_logs(THD* thd)
goto err;
}
+ reset_pending= TRUE;
+ /*
+ send update signal just in case so that all reader threads waiting
+ for log update will leave wait condition
+ */
+ signal_update();
+ /*
+ if there are active readers wait until all of them will
+ release opened files
+ */
+ while (readers_count)
+ pthread_cond_wait(&reset_cond, &LOCK_log);
+
for (;;)
{
my_delete(linfo.log_file_name, MYF(MY_WME));
@@ -973,7 +998,10 @@ bool MYSQL_LOG::reset_logs(THD* thd)
my_free((gptr) save_name, MYF(0));
err:
+ reset_pending= FALSE;
+
(void) pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_mutex_unlock(&LOCK_readers);
pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
@@ -1354,7 +1382,8 @@ void MYSQL_LOG::new_file(bool need_lock)
to change base names at some point.
*/
THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
- Rotate_log_event r(thd,new_name+dirname_length(new_name));
+ Rotate_log_event r(thd,new_name+dirname_length(new_name),
+ 0, LOG_EVENT_OFFSET, 0);
r.write(&log_file);
bytes_written += r.data_written;
}
@@ -1433,7 +1462,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
- pthread_mutex_lock(&LOCK_log);
+ safe_mutex_assert_owner(&LOCK_log);
do
{
if (my_b_append(&log_file,(byte*) buf,len))
@@ -1448,7 +1477,6 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
new_file(0);
err:
- pthread_mutex_unlock(&LOCK_log);
if (!error)
signal_update();
DBUG_RETURN(error);
@@ -2047,6 +2075,13 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave)
{
const char *old_msg;
DBUG_ENTER("wait_for_update");
+
+ if (reset_pending)
+ {
+ pthread_mutex_unlock(&LOCK_log);
+ DBUG_VOID_RETURN;
+ }
+
old_msg= thd->enter_cond(&update_cond, &LOCK_log,
is_slave ?
"Has read all relay log; waiting for the slave I/O "
@@ -2297,6 +2332,32 @@ void MYSQL_LOG::signal_update()
DBUG_VOID_RETURN;
}
+void MYSQL_LOG::readers_addref()
+{
+ /*
+ There is no necessity for reference counting on *nix, since it allows to
+ delete opened files, however it is more clean way to wait
+ untill all files will be closed on *nix as well.
+ */
+ DBUG_ENTER("MYSQL_LOG::reader_addref");
+ pthread_mutex_lock(&LOCK_log);
+ pthread_mutex_lock(&LOCK_readers);
+ readers_count++;
+ pthread_mutex_unlock(&LOCK_readers);
+ pthread_mutex_unlock(&LOCK_log);
+ DBUG_VOID_RETURN;
+}
+
+void MYSQL_LOG::readers_release()
+{
+ DBUG_ENTER("MYSQL_LOG::reader_release");
+ pthread_mutex_lock(&LOCK_log);
+ readers_count--;
+ if (!readers_count)
+ pthread_cond_broadcast(&reset_cond);
+ pthread_mutex_unlock(&LOCK_log);
+ DBUG_VOID_RETURN;
+}
#ifdef __NT__
void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7ee505939f0..081b498f01e 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -122,8 +122,9 @@ static char *pretty_print_str(char *packet, char *str, int len)
static inline char* slave_load_file_stem(char*buf, uint file_id,
int event_server_id)
{
- fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "",
- MY_UNPACK_FILENAME | MY_UNIX_PATH);
+ fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME);
+ to_unix_path(buf);
+
buf = strend(buf);
buf = int10_to_str(::server_id, buf, 10);
*buf++ = '-';
@@ -212,24 +213,18 @@ static inline int read_str(char **buf, char *buf_end, char **str,
/*
Transforms a string into "" or its expression in 0x... form.
*/
+
char *str_to_hex(char *to, const char *from, uint len)
{
- char *p= to;
if (len)
{
- p= strmov(p, "0x");
- for (uint i= 0; i < len; i++, p+= 2)
- {
- /* val[i] is char. Casting to uchar helps greatly if val[i] < 0 */
- uint tmp= (uint) (uchar) from[i];
- p[0]= _dig_vec_upper[tmp >> 4];
- p[1]= _dig_vec_upper[tmp & 15];
- }
- *p= 0;
+ *to++= '0';
+ *to++= 'x';
+ to= octet2hex(to, from, len);
}
else
- p= strmov(p, "\"\"");
- return p; // pointer to end 0 of 'to'
+ to= strmov(to, "\"\"");
+ return to; // pointer to end 0 of 'to'
}
/*
@@ -702,7 +697,6 @@ failed my_b_read"));
*/
DBUG_RETURN(0);
}
-
uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= 0;
const char *error= 0;
@@ -882,15 +876,76 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
Log_event::print_header()
*/
-void Log_event::print_header(FILE* file)
+void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
char llbuff[22];
+ my_off_t hexdump_from= print_event_info->hexdump_from;
+
fputc('#', file);
print_timestamp(file);
fprintf(file, " server id %d end_log_pos %s ", server_id,
- llstr(log_pos,llbuff));
+ llstr(log_pos,llbuff));
+
+ /* mysqlbinlog --hexdump */
+ if (print_event_info->hexdump_from)
+ {
+ fprintf(file, "\n");
+ uchar *ptr= (uchar*)temp_buf;
+ my_off_t size=
+ uint4korr(ptr + EVENT_LEN_OFFSET) - LOG_EVENT_MINIMAL_HEADER_LEN;
+ my_off_t i;
+
+ /* Header len * 4 >= header len * (2 chars + space + extra space) */
+ char *h, hex_string[LOG_EVENT_MINIMAL_HEADER_LEN*4]= {0};
+ char *c, char_string[16+1]= {0};
+
+ /* Pretty-print event common header if header is exactly 19 bytes */
+ if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN)
+ {
+ fprintf(file, "# Position Timestamp Type Master ID "
+ "Size Master Pos Flags \n");
+ fprintf(file, "# %8.8lx %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x\n",
+ hexdump_from, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4],
+ ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11],
+ ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18]);
+ ptr += LOG_EVENT_MINIMAL_HEADER_LEN;
+ hexdump_from += LOG_EVENT_MINIMAL_HEADER_LEN;
+ }
+
+ /* Rest of event (without common header) */
+ for (i= 0, c= char_string, h=hex_string;
+ i < size;
+ i++, ptr++)
+ {
+ my_snprintf(h, 4, "%02x ", *ptr);
+ h += 3;
+
+ *c++= my_isalnum(&my_charset_bin, *ptr) ? *ptr : '.';
+
+ if (i % 16 == 15)
+ {
+ fprintf(file, "# %8.8lx %-48.48s |%16s|\n",
+ hexdump_from + (i & 0xfffffff0), hex_string, char_string);
+ hex_string[0]= 0;
+ char_string[0]= 0;
+ c= char_string;
+ h= hex_string;
+ }
+ else if (i % 8 == 7) *h++ = ' ';
+ }
+ *c= '\0';
+
+ /* Non-full last line */
+ if (hex_string[0]) {
+ printf("# %8.8lx %-48.48s |%s|\n# ",
+ hexdump_from + (i & 0xfffffff0), hex_string, char_string);
+ }
+ }
}
+
/*
Log_event::print_timestamp()
*/
@@ -1166,7 +1221,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
But it's likely that we don't want to use 32 bits for 3 bits; in the future
we will probably want to reclaim the 29 bits. So we need the &.
*/
- flags2= thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG;
+ flags2= (uint32) (thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG);
DBUG_ASSERT(thd->variables.character_set_client->number < 256*256);
DBUG_ASSERT(thd->variables.collation_connection->number < 256*256);
DBUG_ASSERT(thd->variables.collation_server->number < 256*256);
@@ -1373,25 +1428,25 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
*/
#ifdef MYSQL_CLIENT
-void Query_log_event::print_query_header(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Query_log_event::print_query_header(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
{
// TODO: print the catalog ??
char buff[40],*end; // Enough for SET TIMESTAMP
bool different_db= 1;
uint32 tmp;
- if (!short_form)
+ if (!print_event_info->short_form)
{
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
get_type_str(), (ulong) thread_id, (ulong) exec_time, error_code);
}
if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db)
{
- if (different_db= memcmp(last_event_info->db, db, db_len + 1))
- memcpy(last_event_info->db, db, db_len + 1);
+ if (different_db= memcmp(print_event_info->db, db, db_len + 1))
+ memcpy(print_event_info->db, db, db_len + 1);
if (db[0] && different_db)
fprintf(file, "use %s;\n", db);
}
@@ -1411,12 +1466,12 @@ void Query_log_event::print_query_header(FILE* file, bool short_form,
if (likely(flags2_inited)) /* likely as this will mainly read 5.0 logs */
{
/* tmp is a bitmask of bits which have changed. */
- if (likely(last_event_info->flags2_inited))
+ if (likely(print_event_info->flags2_inited))
/* All bits which have changed */
- tmp= (last_event_info->flags2) ^ flags2;
+ tmp= (print_event_info->flags2) ^ flags2;
else /* that's the first Query event we read */
{
- last_event_info->flags2_inited= 1;
+ print_event_info->flags2_inited= 1;
tmp= ~((uint32)0); /* all bits have changed */
}
@@ -1431,7 +1486,7 @@ void Query_log_event::print_query_header(FILE* file, bool short_form,
print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
"@@session.unique_checks", &need_comma);
fprintf(file,";\n");
- last_event_info->flags2= flags2;
+ print_event_info->flags2= flags2;
}
}
@@ -1450,37 +1505,37 @@ void Query_log_event::print_query_header(FILE* file, bool short_form,
if (likely(sql_mode_inited))
{
- if (unlikely(!last_event_info->sql_mode_inited)) /* first Query event */
+ if (unlikely(!print_event_info->sql_mode_inited)) /* first Query event */
{
- last_event_info->sql_mode_inited= 1;
+ print_event_info->sql_mode_inited= 1;
/* force a difference to force write */
- last_event_info->sql_mode= ~sql_mode;
+ print_event_info->sql_mode= ~sql_mode;
}
- if (unlikely(last_event_info->sql_mode != sql_mode))
+ if (unlikely(print_event_info->sql_mode != sql_mode))
{
fprintf(file,"SET @@session.sql_mode=%lu;\n",(ulong)sql_mode);
- last_event_info->sql_mode= sql_mode;
+ print_event_info->sql_mode= sql_mode;
}
}
- if (last_event_info->auto_increment_increment != auto_increment_increment ||
- last_event_info->auto_increment_offset != auto_increment_offset)
+ if (print_event_info->auto_increment_increment != auto_increment_increment ||
+ print_event_info->auto_increment_offset != auto_increment_offset)
{
fprintf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu;\n",
auto_increment_increment,auto_increment_offset);
- last_event_info->auto_increment_increment= auto_increment_increment;
- last_event_info->auto_increment_offset= auto_increment_offset;
+ print_event_info->auto_increment_increment= auto_increment_increment;
+ print_event_info->auto_increment_offset= auto_increment_offset;
}
/* TODO: print the catalog when we feature SET CATALOG */
if (likely(charset_inited))
{
- if (unlikely(!last_event_info->charset_inited)) /* first Query event */
+ if (unlikely(!print_event_info->charset_inited)) /* first Query event */
{
- last_event_info->charset_inited= 1;
- last_event_info->charset[0]= ~charset[0]; // force a difference to force write
+ print_event_info->charset_inited= 1;
+ print_event_info->charset[0]= ~charset[0]; // force a difference to force write
}
- if (unlikely(bcmp(last_event_info->charset, charset, 6)))
+ if (unlikely(bcmp(print_event_info->charset, charset, 6)))
{
fprintf(file,"SET "
"@@session.character_set_client=%d,"
@@ -1490,24 +1545,23 @@ void Query_log_event::print_query_header(FILE* file, bool short_form,
uint2korr(charset),
uint2korr(charset+2),
uint2korr(charset+4));
- memcpy(last_event_info->charset, charset, 6);
+ memcpy(print_event_info->charset, charset, 6);
}
}
if (time_zone_len)
{
- if (bcmp(last_event_info->time_zone_str, time_zone_str, time_zone_len+1))
+ if (bcmp(print_event_info->time_zone_str, time_zone_str, time_zone_len+1))
{
fprintf(file,"SET @@session.time_zone='%s';\n", time_zone_str);
- memcpy(last_event_info->time_zone_str, time_zone_str, time_zone_len+1);
+ memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
}
}
}
-void Query_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- print_query_header(file, short_form, last_event_info);
+ print_query_header(file, print_event_info);
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
fputs(";\n", file);
}
@@ -1805,11 +1859,11 @@ void Start_log_event_v3::pack_info(Protocol *protocol)
*/
#ifdef MYSQL_CLIENT
-void Start_log_event_v3::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- if (!short_form)
+ if (!print_event_info->short_form)
{
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
server_version);
print_timestamp(file);
@@ -2533,19 +2587,19 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
*/
#ifdef MYSQL_CLIENT
-void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- print(file, short_form, last_event_info, 0);
+ print(file, print_event_info, 0);
}
-void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info,
+void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info,
bool commented)
{
DBUG_ENTER("Load_log_event::print");
- if (!short_form)
+ if (!print_event_info->short_form)
{
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
thread_id, exec_time);
}
@@ -2559,9 +2613,9 @@ void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev
But if commented, the "use" is going to be commented so we should not
update the last_db.
*/
- if ((different_db= memcmp(last_event_info->db, db, db_len + 1)) &&
+ if ((different_db= memcmp(print_event_info->db, db, db_len + 1)) &&
!commented)
- memcpy(last_event_info->db, db, db_len + 1);
+ memcpy(print_event_info->db, db, db_len + 1);
}
if (db && db[0] && different_db)
@@ -2950,13 +3004,13 @@ void Rotate_log_event::pack_info(Protocol *protocol)
*/
#ifdef MYSQL_CLIENT
-void Rotate_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
char buf[22];
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tRotate to ");
if (new_log_ident)
my_fwrite(file, (byte*) new_log_ident, (uint)ident_len,
@@ -2968,13 +3022,38 @@ void Rotate_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_
#endif /* MYSQL_CLIENT */
+
/*
- Rotate_log_event::Rotate_log_event()
+ Rotate_log_event::Rotate_log_event() (2 constructors)
*/
+
+#ifndef MYSQL_CLIENT
+Rotate_log_event::Rotate_log_event(THD* thd_arg,
+ const char* new_log_ident_arg,
+ uint ident_len_arg, ulonglong pos_arg,
+ uint flags_arg)
+ :Log_event(), new_log_ident(new_log_ident_arg),
+ pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
+ (uint) strlen(new_log_ident_arg)), flags(flags_arg)
+{
+#ifndef DBUG_OFF
+ char buff[22];
+ DBUG_ENTER("Rotate_log_event::Rotate_log_event(THD*,...)");
+ DBUG_PRINT("enter",("new_log_ident %s pos %s flags %lu", new_log_ident_arg,
+ llstr(pos_arg, buff), flags));
+#endif
+ if (flags & DUP_NAME)
+ new_log_ident= my_strdup_with_length((const byte*) new_log_ident_arg,
+ ident_len, MYF(MY_WME));
+ DBUG_VOID_RETURN;
+}
+#endif
+
+
Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)
- :Log_event(buf, description_event) ,new_log_ident(NULL),alloced(0)
+ :Log_event(buf, description_event) ,new_log_ident(0), flags(DUP_NAME)
{
DBUG_ENTER("Rotate_log_event::Rotate_log_event(char*,...)");
// The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
@@ -2989,12 +3068,9 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
(header_size+post_header_len));
ident_offset = post_header_len;
set_if_smaller(ident_len,FN_REFLEN-1);
- if (!(new_log_ident= my_strdup_with_length((byte*) buf +
- ident_offset,
- (uint) ident_len,
- MYF(MY_WME))))
- DBUG_VOID_RETURN;
- alloced = 1;
+ new_log_ident= my_strdup_with_length((byte*) buf + ident_offset,
+ (uint) ident_len,
+ MYF(MY_WME));
DBUG_VOID_RETURN;
}
@@ -3152,16 +3228,15 @@ bool Intvar_log_event::write(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void Intvar_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
char llbuff[22];
const char *msg;
LINT_INIT(msg);
- if (!short_form)
+ if (!print_event_info->short_form)
{
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tIntvar\n");
}
@@ -3242,12 +3317,12 @@ bool Rand_log_event::write(IO_CACHE* file)
#ifdef MYSQL_CLIENT
-void Rand_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
char llbuff[22],llbuff2[22];
- if (!short_form)
+ if (!print_event_info->short_form)
{
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tRand\n");
}
fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
@@ -3312,14 +3387,14 @@ bool Xid_log_event::write(IO_CACHE* file)
#ifdef MYSQL_CLIENT
-void Xid_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- if (!short_form)
+ if (!print_event_info->short_form)
{
char buf[64];
longlong10_to_str(xid, buf, 10);
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tXid = %s\n", buf);
fflush(file);
}
@@ -3510,11 +3585,11 @@ bool User_var_log_event::write(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- if (!short_form)
+ if (!print_event_info->short_form)
{
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tUser_var\n");
}
@@ -3685,11 +3760,11 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
#ifdef HAVE_REPLICATION
#ifdef MYSQL_CLIENT
-void Unknown_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Unknown_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fputc('\n', file);
fprintf(file, "# %s", "Unknown event\n");
}
@@ -3756,12 +3831,12 @@ Slave_log_event::~Slave_log_event()
#ifdef MYSQL_CLIENT
-void Slave_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Slave_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
char llbuff[22];
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fputc('\n', file);
fprintf(file, "\
Slave: master_host: '%s' master_port: %d master_log: '%s' master_pos: %s\n",
@@ -3841,12 +3916,12 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli)
*/
#ifdef MYSQL_CLIENT
-void Stop_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fprintf(file, "\tStop\n");
fflush(file);
}
@@ -4020,19 +4095,20 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
*/
#ifdef MYSQL_CLIENT
-void Create_file_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info, bool enable_local)
+void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info,
+ bool enable_local)
{
- if (short_form)
+ if (print_event_info->short_form)
{
if (enable_local && check_fname_outside_temp_buf())
- Load_log_event::print(file, 1, last_event_info);
+ Load_log_event::print(file, print_event_info);
return;
}
if (enable_local)
{
- Load_log_event::print(file, short_form, last_event_info, !check_fname_outside_temp_buf());
+ Load_log_event::print(file, print_event_info,
+ !check_fname_outside_temp_buf());
/*
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
@@ -4044,10 +4120,9 @@ void Create_file_log_event::print(FILE* file, bool short_form,
}
-void Create_file_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- print(file,short_form,last_event_info,0);
+ print(file, print_event_info, 0);
}
#endif /* MYSQL_CLIENT */
@@ -4207,12 +4282,12 @@ bool Append_block_log_event::write(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void Append_block_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Append_block_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
{
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fputc('\n', file);
fprintf(file, "#%s: file_id: %d block_len: %d\n",
get_type_str(), file_id, block_len);
@@ -4351,12 +4426,12 @@ bool Delete_file_log_event::write(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void Delete_file_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Delete_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
{
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fputc('\n', file);
fprintf(file, "#Delete_file: file_id=%u\n", file_id);
}
@@ -4447,12 +4522,12 @@ bool Execute_load_log_event::write(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void Execute_load_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Execute_load_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
{
- if (short_form)
+ if (print_event_info->short_form)
return;
- print_header(file);
+ print_header(file, print_event_info);
fputc('\n', file);
fprintf(file, "#Exec_load: file_id=%d\n",
file_id);
@@ -4659,18 +4734,18 @@ Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
#ifdef MYSQL_CLIENT
-void Execute_load_query_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info)
+void Execute_load_query_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
{
- print(file, short_form, last_event_info, 0);
+ print(file, print_event_info, 0);
}
-void Execute_load_query_log_event::print(FILE* file, bool short_form,
- LAST_EVENT_INFO* last_event_info,
+void Execute_load_query_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info,
const char *local_fname)
{
- print_query_header(file, short_form, last_event_info);
+ print_query_header(file, print_event_info);
if (local_fname)
{
@@ -4691,7 +4766,7 @@ void Execute_load_query_log_event::print(FILE* file, bool short_form,
fprintf(file, ";\n");
}
- if (!short_form)
+ if (!print_event_info->short_form)
fprintf(file, "# file_id: %d \n", file_id);
}
#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index 29580589a34..7783a97f03f 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -403,24 +403,34 @@ enum Log_event_type
Every time you update this enum (when you add a type), you have to
fix Format_description_log_event::Format_description_log_event().
*/
- UNKNOWN_EVENT= 0, START_EVENT_V3, QUERY_EVENT, STOP_EVENT, ROTATE_EVENT,
- INTVAR_EVENT, LOAD_EVENT, SLAVE_EVENT, CREATE_FILE_EVENT,
- APPEND_BLOCK_EVENT, EXEC_LOAD_EVENT, DELETE_FILE_EVENT,
+ UNKNOWN_EVENT= 0,
+ START_EVENT_V3= 1,
+ QUERY_EVENT= 2,
+ STOP_EVENT= 3,
+ ROTATE_EVENT= 4,
+ INTVAR_EVENT= 5,
+ LOAD_EVENT= 6,
+ SLAVE_EVENT= 7,
+ CREATE_FILE_EVENT= 8,
+ APPEND_BLOCK_EVENT= 9,
+ EXEC_LOAD_EVENT= 10,
+ DELETE_FILE_EVENT= 11,
/*
NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer
sql_ex, allowing multibyte TERMINATED BY etc; both types share the
same class (Load_log_event)
*/
- NEW_LOAD_EVENT,
- RAND_EVENT, USER_VAR_EVENT,
- FORMAT_DESCRIPTION_EVENT,
- XID_EVENT,
- BEGIN_LOAD_QUERY_EVENT,
- EXECUTE_LOAD_QUERY_EVENT,
+ NEW_LOAD_EVENT= 12,
+ RAND_EVENT= 13,
+ USER_VAR_EVENT= 14,
+ FORMAT_DESCRIPTION_EVENT= 15,
+ XID_EVENT= 16,
+ BEGIN_LOAD_QUERY_EVENT= 17,
+ EXECUTE_LOAD_QUERY_EVENT= 18,
/*
- add new events here - right above this comment!
- existing events should never change their numbers
+ Add new events here - right above this comment!
+ Existing events (except ENUM_END_EVENT) should never change their numbers
*/
ENUM_END_EVENT /* end marker */
@@ -451,12 +461,23 @@ struct st_relay_log_info;
#ifdef MYSQL_CLIENT
/*
- A structure for mysqlbinlog to remember the last db, flags2, sql_mode etc; it
- is passed to events' print() methods, so that they print only the necessary
- USE and SET commands.
+ A structure for mysqlbinlog to know how to print events
+
+ This structure is passed to the event's print() methods,
+
+ There are two types of settings stored here:
+ 1. Last db, flags2, sql_mode etc comes from the last printed event.
+ They are stored so that only the necessary USE and SET commands
+ are printed.
+ 2. Other information on how to print the events, e.g. short_form,
+ hexdump_from. These are not dependent on the last event.
*/
-typedef struct st_last_event_info
+typedef struct st_print_event_info
{
+ /*
+ Settings for database, sql_mode etc that comes from the last event
+ that was printed.
+ */
// TODO: have the last catalog here ??
char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is
bool flags2_inited;
@@ -467,12 +488,12 @@ typedef struct st_last_event_info
bool charset_inited;
char charset[6]; // 3 variables, each of them storable in 2 bytes
char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
- st_last_event_info()
+ st_print_event_info()
:flags2_inited(0), sql_mode_inited(0),
auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
{
/*
- Currently we only use static LAST_EVENT_INFO objects, so zeroed at
+ Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
program's startup, but these explicit bzero() is for the day someone
creates dynamic instances.
*/
@@ -480,7 +501,13 @@ typedef struct st_last_event_info
bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str));
}
-} LAST_EVENT_INFO;
+
+ /* Settings on how to print the events */
+ bool short_form;
+ my_off_t hexdump_from;
+ uint8 common_header_len;
+
+} PRINT_EVENT_INFO;
#endif
@@ -589,9 +616,9 @@ public:
static Log_event* read_log_event(IO_CACHE* file,
const Format_description_log_event *description_event);
/* print*() functions are used by mysqlbinlog */
- virtual void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0) = 0;
+ virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0) = 0;
void print_timestamp(FILE* file, time_t *ts = 0);
- void print_header(FILE* file);
+ void print_header(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
static void *operator new(size_t size)
@@ -751,8 +778,8 @@ public:
uint32 q_len_arg);
#endif /* HAVE_REPLICATION */
#else
- void print_query_header(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print_query_header(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Query_log_event(const char* buf, uint event_len,
@@ -806,7 +833,7 @@ public:
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Slave_log_event(const char* buf, uint event_len);
@@ -894,8 +921,8 @@ public:
bool use_rli_only_for_errors);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info = 0);
- void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool commented);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info = 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool commented);
#endif
/*
@@ -984,7 +1011,7 @@ public:
#endif /* HAVE_REPLICATION */
#else
Start_log_event_v3() {}
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Start_log_event_v3(const char* buf,
@@ -1079,7 +1106,7 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Intvar_log_event(const char* buf, const Format_description_log_event* description_event);
@@ -1120,7 +1147,7 @@ class Rand_log_event: public Log_event
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Rand_log_event(const char* buf, const Format_description_log_event* description_event);
@@ -1157,7 +1184,7 @@ class Xid_log_event: public Log_event
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Xid_log_event(const char* buf, const Format_description_log_event* description_event);
@@ -1199,7 +1226,7 @@ public:
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
User_var_log_event(const char* buf, const Format_description_log_event* description_event);
@@ -1225,7 +1252,7 @@ public:
{}
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Stop_log_event(const char* buf, const Format_description_log_event* description_event):
@@ -1247,32 +1274,31 @@ public:
class Rotate_log_event: public Log_event
{
public:
+ enum {
+ DUP_NAME= 2 // if constructor should dup the string argument
+ };
const char* new_log_ident;
ulonglong pos;
uint ident_len;
- bool alloced;
+ uint flags;
#ifndef MYSQL_CLIENT
Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg,
- uint ident_len_arg = 0,
- ulonglong pos_arg = LOG_EVENT_OFFSET)
- :Log_event(), new_log_ident(new_log_ident_arg),
- pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
- (uint) strlen(new_log_ident_arg)), alloced(0)
- {}
+ uint ident_len_arg,
+ ulonglong pos_arg, uint flags);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Rotate_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event);
~Rotate_log_event()
{
- if (alloced)
- my_free((gptr) new_log_ident, MYF(0));
+ if (flags & DUP_NAME)
+ my_free((gptr) new_log_ident, MYF(MY_ALLOW_ZERO_PTR));
}
Log_event_type get_type_code() { return ROTATE_EVENT;}
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
@@ -1317,8 +1343,8 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
- void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool enable_local);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool enable_local);
#endif
Create_file_log_event(const char* buf, uint event_len,
@@ -1385,7 +1411,7 @@ public:
virtual int get_create_or_append() const;
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Append_block_log_event(const char* buf, uint event_len,
@@ -1420,8 +1446,8 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
- void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool enable_local);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool enable_local);
#endif
Delete_file_log_event(const char* buf, uint event_len,
@@ -1456,7 +1482,7 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
#endif
Execute_load_log_event(const char* buf, uint event_len,
@@ -1541,11 +1567,10 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0,
- LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
/* Prints the query as LOAD DATA LOCAL and with rewritten filename */
- void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info,
- const char *local_fname);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info,
+ const char *local_fname);
#endif
Execute_load_query_log_event(const char* buf, uint event_len,
const Format_description_log_event *description_event);
@@ -1574,7 +1599,7 @@ public:
Log_event(buf, description_event)
{}
~Unknown_log_event() {}
- void print(FILE* file, bool short_form= 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0);
Log_event_type get_type_code() { return UNKNOWN_EVENT;}
bool is_valid() const { return 1; }
};
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index f188d27ff78..1bd16940b47 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -185,7 +185,7 @@ int str2my_decimal(uint mask, const char *from, uint length,
}
}
}
- check_result(mask, err);
+ check_result_and_overflow(mask, err, decimal_value);
return err;
}
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index b65e6aedaa2..b02abacf0a3 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -126,6 +126,19 @@ inline int decimal_operation_results(int result)
}
#endif /*MYSQL_CLIENT*/
+inline
+void max_my_decimal(my_decimal *to, int precision, int frac)
+{
+ DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&&
+ (frac <= DECIMAL_MAX_SCALE));
+ max_decimal(precision, frac, (decimal_t*) to);
+}
+
+inline void max_internal_decimal(my_decimal *to)
+{
+ max_my_decimal(to, DECIMAL_MAX_PRECISION, 0);
+}
+
inline int check_result(uint mask, int result)
{
if (result & mask)
@@ -133,6 +146,18 @@ inline int check_result(uint mask, int result)
return result;
}
+inline int check_result_and_overflow(uint mask, int result, my_decimal *val)
+{
+ if (check_result(mask, result) & E_DEC_OVERFLOW)
+ {
+ bool sign= val->sign();
+ val->fix_buffer_pointer();
+ max_internal_decimal(val);
+ val->sign(sign);
+ }
+ return result;
+}
+
inline uint my_decimal_length_to_precision(uint length, uint scale,
bool unsigned_flag)
{
@@ -256,7 +281,8 @@ int my_decimal2double(uint mask, const my_decimal *d, double *result)
inline
int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end)
{
- return check_result(mask, string2decimal(str, (decimal_t*) d, end));
+ return check_result_and_overflow(mask, string2decimal(str,(decimal_t*)d,end),
+ d);
}
@@ -274,7 +300,7 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d)
inline
int double2my_decimal(uint mask, double val, my_decimal *d)
{
- return check_result(mask, double2decimal(val, (decimal_t*) d));
+ return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d);
}
@@ -303,7 +329,9 @@ inline
int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b)
{
- return check_result(mask, decimal_add((decimal_t*) a, (decimal_t*) b, res));
+ return check_result_and_overflow(mask,
+ decimal_add((decimal_t*)a,(decimal_t*)b,res),
+ res);
}
@@ -311,7 +339,9 @@ inline
int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b)
{
- return check_result(mask, decimal_sub((decimal_t*) a, (decimal_t*) b, res));
+ return check_result_and_overflow(mask,
+ decimal_sub((decimal_t*)a,(decimal_t*)b,res),
+ res);
}
@@ -319,7 +349,9 @@ inline
int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b)
{
- return check_result(mask, decimal_mul((decimal_t*) a, (decimal_t*) b, res));
+ return check_result_and_overflow(mask,
+ decimal_mul((decimal_t*)a,(decimal_t*)b,res),
+ res);
}
@@ -327,8 +359,10 @@ inline
int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b, int div_scale_inc)
{
- return check_result(mask, decimal_div((decimal_t*) a, (decimal_t*) b, res,
- div_scale_inc));
+ return check_result_and_overflow(mask,
+ decimal_div((decimal_t*)a,(decimal_t*)b,res,
+ div_scale_inc),
+ res);
}
@@ -336,7 +370,9 @@ inline
int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b)
{
- return check_result(mask, decimal_mod((decimal_t*) a, (decimal_t*) b, res));
+ return check_result_and_overflow(mask,
+ decimal_mod((decimal_t*)a,(decimal_t*)b,res),
+ res);
}
@@ -347,13 +383,5 @@ int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
return decimal_cmp((decimal_t*) a, (decimal_t*) b);
}
-inline
-void max_my_decimal(my_decimal *to, int precision, int frac)
-{
- DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&&
- (frac <= DECIMAL_MAX_SCALE));
- max_decimal(precision, frac, (decimal_t*) to);
-}
-
#endif /*my_decimal_h*/
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 0110cb70892..a967e2ee7fe 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -702,11 +702,11 @@ int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
bool mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
-int mysql_handle_derived(LEX *lex, int (*processor)(THD *thd,
- LEX *lex,
- TABLE_LIST *table));
-int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
-int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
+bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
+ LEX *lex,
+ TABLE_LIST *table));
+bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
+bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
bool group, bool modify_item,
@@ -780,7 +780,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
bool *refresh, uint flags);
-TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table);
+bool reopen_name_locked_table(THD* thd, TABLE_LIST* table);
TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
bool reopen_table(TABLE *table,bool locked);
bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
@@ -816,8 +816,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
Field *
find_field_in_table(THD *thd, TABLE *table, const char *name,
uint length, bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr);
-
+ uint *cached_field_index_ptr,
+ Security_context *sctx);
Field *
find_field_in_table_sef(TABLE *table, const char *name);
@@ -1323,7 +1323,6 @@ int openfrm(THD *thd, const char *name,const char *alias,uint filestat,
int readfrm(const char *name, const void** data, uint* length);
int writefrm(const char* name, const void* data, uint len);
int closefrm(TABLE *table);
-db_type get_table_type(THD *thd, const char *name);
int read_string(File file, gptr *to, uint length);
void free_blobs(TABLE *table);
int set_zone(int nr,int min_zone,int max_zone);
@@ -1362,6 +1361,8 @@ void change_byte(byte *,uint,char,char);
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
SQL_SELECT *select,
int use_record_cache, bool print_errors);
+void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
+ bool print_error, uint idx);
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,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 47184a577ee..660e83db7d1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -585,6 +585,20 @@ HANDLE smem_event_connect_request= 0;
#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
+#include <openssl/crypto.h>
+#ifndef HAVE_YASSL
+typedef struct CRYPTO_dynlock_value
+{
+ rw_lock_t lock;
+} openssl_lock_t;
+
+static openssl_lock_t *openssl_stdlocks;
+static openssl_lock_t *openssl_dynlock_create(const char *, int);
+static void openssl_dynlock_destroy(openssl_lock_t *, const char *, int);
+static void openssl_lock_function(int, int, const char *, int);
+static void openssl_lock(int, openssl_lock_t *, const char *, int);
+static unsigned long openssl_id_function();
+#endif
char *des_key_file;
struct st_VioSSLAcceptorFd *ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
@@ -920,7 +934,7 @@ static void __cdecl kill_server(int sig_ptr)
RETURN_FROM_KILL_SERVER;
kill_in_progress=TRUE;
abort_loop=1; // This should be set
- signal(sig,SIG_IGN);
+ my_sigset(sig,SIG_IGN);
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
else
@@ -969,11 +983,6 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
}
#endif
-#if defined(__amiga__)
-#undef sigset
-#define sigset signal
-#endif
-
extern "C" sig_handler print_signal_warning(int sig)
{
if (!DBUG_IN_USE)
@@ -983,7 +992,7 @@ extern "C" sig_handler print_signal_warning(int sig)
sig,my_thread_id());
}
#ifdef DONT_REMEMBER_SIGNAL
- sigset(sig,print_signal_warning); /* int. thread system calls */
+ my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
if (sig == SIGALRM)
@@ -1173,6 +1182,11 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_user_conn);
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
+#ifndef HAVE_YASSL
+ for (int i= 0; i < CRYPTO_num_locks(); ++i)
+ (void) rwlock_destroy(&openssl_stdlocks[i].lock);
+ OPENSSL_free(openssl_stdlocks);
+#endif
#endif
#ifdef HAVE_REPLICATION
(void) pthread_mutex_destroy(&LOCK_rpl_status);
@@ -1183,6 +1197,7 @@ static void clean_up_mutexes()
(void) rwlock_destroy(&LOCK_sys_init_slave);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
(void) pthread_mutex_destroy(&LOCK_global_read_lock);
+ (void) pthread_mutex_destroy(&LOCK_uuid_generator);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
(void) pthread_cond_destroy(&COND_thread_cache);
@@ -2058,8 +2073,8 @@ static void init_signals(void)
DBUG_ENTER("init_signals");
if (test_flags & TEST_SIGINT)
- sigset(THR_KILL_SIGNAL,end_thread_signal);
- sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
+ my_sigset(THR_KILL_SIGNAL,end_thread_signal);
+ my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
{
@@ -2093,13 +2108,8 @@ static void init_signals(void)
}
#endif
(void) sigemptyset(&set);
-#ifdef THREAD_SPECIFIC_SIGPIPE
- sigset(SIGPIPE,abort_thread);
+ my_sigset(SIGPIPE,SIG_IGN);
sigaddset(&set,SIGPIPE);
-#else
- (void) signal(SIGPIPE,SIG_IGN); // Can't know which thread
- sigaddset(&set,SIGPIPE);
-#endif
sigaddset(&set,SIGINT);
#ifndef IGNORE_SIGHUP_SIGQUIT
sigaddset(&set,SIGQUIT);
@@ -2326,6 +2336,8 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
if (thd->spcont &&
thd->spcont->find_handler(error, MYSQL_ERROR::WARN_LEVEL_ERROR))
{
+ if (! thd->spcont->found_handler_here())
+ thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_RETURN(0);
}
@@ -2729,6 +2741,17 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
#ifdef HAVE_OPENSSL
(void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
+#ifndef HAVE_YASSL
+ openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() *
+ sizeof(openssl_lock_t));
+ for (int i= 0; i < CRYPTO_num_locks(); ++i)
+ (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL);
+ CRYPTO_set_dynlock_create_callback(openssl_dynlock_create);
+ CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy);
+ CRYPTO_set_dynlock_lock_callback(openssl_lock);
+ CRYPTO_set_locking_callback(openssl_lock_function);
+ CRYPTO_set_id_callback(openssl_id_function);
+#endif
#endif
(void) my_rwlock_init(&LOCK_sys_init_connect, NULL);
(void) my_rwlock_init(&LOCK_sys_init_slave, NULL);
@@ -2761,6 +2784,75 @@ static int init_thread_environment()
}
+#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL)
+static unsigned long openssl_id_function()
+{
+ return (unsigned long) pthread_self();
+}
+
+
+static openssl_lock_t *openssl_dynlock_create(const char *file, int line)
+{
+ openssl_lock_t *lock= new openssl_lock_t;
+ my_rwlock_init(&lock->lock, NULL);
+ return lock;
+}
+
+
+static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file,
+ int line)
+{
+ rwlock_destroy(&lock->lock);
+ delete lock;
+}
+
+
+static void openssl_lock_function(int mode, int n, const char *file, int line)
+{
+ if (n < 0 || n > CRYPTO_num_locks())
+ {
+ /* Lock number out of bounds. */
+ sql_print_error("Fatal: OpenSSL interface problem (n = %d)", n);
+ abort();
+ }
+ openssl_lock(mode, &openssl_stdlocks[n], file, line);
+}
+
+
+static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
+ int line)
+{
+ int err;
+ char const *what;
+
+ switch (mode) {
+ case CRYPTO_LOCK|CRYPTO_READ:
+ what = "read lock";
+ err = rw_rdlock(&lock->lock);
+ break;
+ case CRYPTO_LOCK|CRYPTO_WRITE:
+ what = "write lock";
+ err = rw_wrlock(&lock->lock);
+ break;
+ case CRYPTO_UNLOCK|CRYPTO_READ:
+ case CRYPTO_UNLOCK|CRYPTO_WRITE:
+ what = "unlock";
+ err = rw_unlock(&lock->lock);
+ break;
+ default:
+ /* Unknown locking mode. */
+ sql_print_error("Fatal: OpenSSL interface problem (mode=0x%x)", mode);
+ abort();
+ }
+ if (err)
+ {
+ sql_print_error("Fatal: can't %s OpenSSL %s lock", what);
+ abort();
+ }
+}
+#endif /* HAVE_OPENSSL */
+
+
static void init_ssl()
{
#ifdef HAVE_OPENSSL
@@ -2772,7 +2864,14 @@ static void init_ssl()
opt_ssl_cipher);
DBUG_PRINT("info",("ssl_acceptor_fd: 0x%lx", (long) ssl_acceptor_fd));
if (!ssl_acceptor_fd)
+ {
opt_use_ssl = 0;
+ have_openssl= SHOW_OPTION_DISABLED;
+ }
+ }
+ else
+ {
+ have_openssl= SHOW_OPTION_DISABLED;
}
if (des_key_file)
load_des_key_file(des_key_file);
@@ -2938,6 +3037,23 @@ server.");
sql_print_error("Can't init databases");
unireg_abort(1);
}
+
+ /*
+ Check that the default storage engine is actually available.
+ */
+ if (!ha_storage_engine_is_enabled((enum db_type)
+ global_system_variables.table_type))
+ {
+ if (!opt_bootstrap)
+ {
+ sql_print_error("Default storage engine (%s) is not available",
+ ha_get_storage_engine((enum db_type)
+ global_system_variables.table_type));
+ unireg_abort(1);
+ }
+ global_system_variables.table_type= DB_TYPE_MYISAM;
+ }
+
tc_log= (total_ha_2pc > 1 ? (opt_bin_log ?
(TC_LOG *) &mysql_bin_log :
(TC_LOG *) &tc_log_mmap) :
@@ -3594,7 +3710,6 @@ static void bootstrap(FILE *file)
THD *thd= new THD;
thd->bootstrap=1;
- thd->client_capabilities=0;
my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet;
thd->security_ctx->master_access= ~(ulong)0;
@@ -5164,7 +5279,7 @@ replicating a LOAD DATA INFILE command.",
{"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option does nothing anymore.",
- 0, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ 0, 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
"Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
(gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
@@ -5560,7 +5675,8 @@ The minimum value for this variable is 4096.",
GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
{"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
"Specifies how MyISAM index statistics collection code should threat NULLs. "
- "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).",
+ "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
+ "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
(gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
@@ -5638,7 +5754,8 @@ The minimum value for this variable is 4096.",
"Persistent buffer for query parsing and execution",
(gptr*) &global_system_variables.query_prealloc_size,
(gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 16384, ~0L, 0, 1024, 0},
+ REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE,
+ ~0L, 0, 1024, 0},
{"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE,
"Allocation block size for storing ranges during optimization",
(gptr*) &global_system_variables.range_alloc_block_size,
@@ -5902,6 +6019,7 @@ struct show_var_st status_vars[]= {
{"Com_xa_recover", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_RECOVER]),SHOW_LONG_STATUS},
{"Com_xa_rollback", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_ROLLBACK]),SHOW_LONG_STATUS},
{"Com_xa_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_START]),SHOW_LONG_STATUS},
+ {"Compression", (char*) 0, SHOW_NET_COMPRESSION},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
{"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables), SHOW_LONG_STATUS},
{"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG},
@@ -6814,6 +6932,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
case OPT_MYISAM_STATS_METHOD:
{
+ ulong method_conv;
myisam_stats_method_str= argument;
int method;
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
@@ -6821,7 +6940,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument);
exit(1);
}
- global_system_variables.myisam_stats_method= method-1;
+ switch (method-1) {
+ case 0:
+ method_conv= MI_STATS_METHOD_NULLS_EQUAL;
+ break;
+ case 1:
+ method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
+ break;
+ case 2:
+ method_conv= MI_STATS_METHOD_IGNORE_NULLS;
+ break;
+ }
+ global_system_variables.myisam_stats_method= method_conv;
break;
}
case OPT_SQL_MODE:
@@ -6929,22 +7059,6 @@ static void get_options(int argc,char **argv)
!opt_slow_log)
sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set");
- /*
- Check that the default storage engine is actually available.
- */
- if (!ha_storage_engine_is_enabled((enum db_type)
- global_system_variables.table_type))
- {
- if (!opt_bootstrap)
- {
- sql_print_error("Default storage engine (%s) is not available",
- ha_get_storage_engine((enum db_type)
- global_system_variables.table_type));
- exit(1);
- }
- global_system_variables.table_type= DB_TYPE_MYISAM;
- }
-
if (argc > 0)
{
fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv);
@@ -7106,6 +7220,7 @@ static void fix_paths(void)
CHARSET_DIR, NullS);
}
(void) my_load_path(mysql_charsets_dir, mysql_charsets_dir, buff);
+ convert_dirname(mysql_charsets_dir, mysql_charsets_dir, NullS);
charsets_dir=mysql_charsets_dir;
if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir))
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 2f4cf1c4752..2400672a3f9 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -932,7 +932,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
}
THD *thd= current_thd;
- if (!(file= get_new_handler(head, head->s->db_type)))
+ if (!(file= get_new_handler(head, thd->mem_root, head->s->db_type)))
goto failure;
DBUG_PRINT("info", ("Allocated new handler %p", file));
if (file->ha_open(head->s->path, head->db_stat, HA_OPEN_IGNORE_IF_LOCKED))
@@ -1366,6 +1366,95 @@ SEL_ARG *SEL_ARG::clone_tree()
/*
+ Find the best index to retrieve first N records in given order
+
+ SYNOPSIS
+ get_index_for_order()
+ table Table to be accessed
+ order Required ordering
+ limit Number of records that will be retrieved
+
+ DESCRIPTION
+ Find the best index that allows to retrieve first #limit records in the
+ given order cheaper then one would retrieve them using full table scan.
+
+ IMPLEMENTATION
+ Run through all table indexes and find the shortest index that allows
+ records to be retrieved in given order. We look for the shortest index
+ as we will have fewer index pages to read with it.
+
+ This function is used only by UPDATE/DELETE, so we take into account how
+ the UPDATE/DELETE code will work:
+ * index can only be scanned in forward direction
+ * HA_EXTRA_KEYREAD will not be used
+ Perhaps these assumptions could be relaxed
+
+ RETURN
+ index number
+ MAX_KEY if no such index was found.
+*/
+
+uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit)
+{
+ uint idx;
+ uint match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1;
+ ORDER *ord;
+
+ for (ord= order; ord; ord= ord->next)
+ if (!ord->asc)
+ return MAX_KEY;
+
+ for (idx= 0; idx < table->s->keys; idx++)
+ {
+ if (!(table->keys_in_use_for_query.is_set(idx)))
+ continue;
+ KEY_PART_INFO *keyinfo= table->key_info[idx].key_part;
+ uint partno= 0;
+
+ /*
+ The below check is sufficient considering we now have either BTREE
+ indexes (records are returned in order for any index prefix) or HASH
+ indexes (records are not returned in order for any index prefix).
+ */
+ if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER))
+ continue;
+ for (ord= order; ord; ord= ord->next, partno++)
+ {
+ Item *item= order->item[0];
+ if (!(item->type() == Item::FIELD_ITEM &&
+ ((Item_field*)item)->field->eq(keyinfo[partno].field)))
+ break;
+ }
+
+ if (!ord && table->key_info[idx].key_length < match_key_len)
+ {
+ /*
+ Ok, the ordering is compatible and this key is shorter then
+ previous match (we want shorter keys as we'll have to read fewer
+ index pages for the same number of records)
+ */
+ match_key= idx;
+ match_key_len= table->key_info[idx].key_length;
+ }
+ }
+
+ if (match_key != MAX_KEY)
+ {
+ /*
+ Found an index that allows records to be retrieved in the requested
+ order. Now we'll check if using the index is cheaper then doing a table
+ scan.
+ */
+ double full_scan_time= table->file->scan_time();
+ double index_scan_time= table->file->read_time(match_key, 1, limit);
+ if (index_scan_time > full_scan_time)
+ match_key= MAX_KEY;
+ }
+ return match_key;
+}
+
+
+/*
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
objects from table read plans.
*/
@@ -3692,6 +3781,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
SEL_ARG *tree= 0;
MEM_ROOT *alloc= param->mem_root;
char *str;
+ ulong orig_sql_mode;
DBUG_ENTER("get_mm_leaf");
/*
@@ -3837,13 +3927,20 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
value->result_type() != STRING_RESULT &&
field->cmp_type() != value->result_type())
goto end;
-
+ /* For comparison purposes allow invalid dates like 2000-01-32 */
+ orig_sql_mode= field->table->in_use->variables.sql_mode;
+ if (value->real_item()->type() == Item::STRING_ITEM &&
+ (field->type() == FIELD_TYPE_DATE ||
+ field->type() == FIELD_TYPE_DATETIME))
+ field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
if (value->save_in_field_no_warnings(field, 1) < 0)
{
+ field->table->in_use->variables.sql_mode= orig_sql_mode;
/* This happens when we try to insert a NULL field in a not null column */
tree= &null_element; // cmp with NULL is never TRUE
goto end;
}
+ field->table->in_use->variables.sql_mode= orig_sql_mode;
str= (char*) alloc_root(alloc, key_part->store_length+1);
if (!str)
goto end;
@@ -7045,19 +7142,15 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (thd->query_id == cur_field->query_id)
{
- bool is_covered= FALSE;
KEY_PART_INFO *key_part= cur_index_info->key_part;
KEY_PART_INFO *key_part_end= key_part + cur_index_info->key_parts;
- for (; key_part != key_part_end ; key_part++)
+ for (;;)
{
if (key_part->field == cur_field)
- {
- is_covered= TRUE;
break;
- }
+ if (++key_part == key_part_end)
+ goto next_index; // Field was not part of key
}
- if (!is_covered)
- goto next_index;
}
}
}
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 37d77033c8d..f84058f3b64 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -716,4 +716,6 @@ public:
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
struct st_table_ref *ref,
ha_rows records);
+uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);
+
#endif
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 5c7053e6e2a..d3e5645bafc 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -372,8 +372,10 @@ my_bool rename_in_schema_file(const char *schema, const char *old_name,
if (revision > 0 && !access(arc_path, F_OK))
{
- ulonglong limit= (revision > num_view_backups) ? revision - num_view_backups : 0;
- while (revision > limit) {
+ ulonglong limit= ((revision > num_view_backups) ?
+ revision - num_view_backups : 0);
+ for (; revision > limit ; revision--)
+ {
my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu",
arc_path, old_name, reg_ext, (ulong)revision);
(void) unpack_filename(old_path, old_path);
@@ -381,7 +383,6 @@ my_bool rename_in_schema_file(const char *schema, const char *old_name,
arc_path, new_name, reg_ext, (ulong)revision);
(void) unpack_filename(new_path, new_path);
my_rename(old_path, new_path, MYF(0));
- revision--;
}
}
return 0;
diff --git a/sql/password.c b/sql/password.c
index aa05be8c740..562df3ae226 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -316,18 +316,21 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st)
octet2hex()
buf OUT output buffer. Must be at least 2*len+1 bytes
str, len IN the beginning and the length of the input string
+
+ RETURN
+ buf+len*2
*/
-void
-octet2hex(char *to, const unsigned char *str, uint len)
+char *octet2hex(char *to, const char *str, uint len)
{
- const uint8 *str_end= str + len;
+ const byte *str_end= str + len;
for (; str != str_end; ++str)
{
- *to++= _dig_vec_upper[(*str & 0xF0) >> 4];
- *to++= _dig_vec_upper[*str & 0x0F];
+ *to++= _dig_vec_upper[((uchar) *str) >> 4];
+ *to++= _dig_vec_upper[((uchar) *str) & 0x0F];
}
*to= '\0';
+ return to;
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index ade94a483a8..8c3e5a62820 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -76,6 +76,8 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
if (thd->spcont && thd->spcont->find_handler(sql_errno,
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
+ if (! thd->spcont->found_handler_here())
+ thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_VOID_RETURN;
}
thd->query_error= 1; // needed to catch query errors during replication
@@ -181,6 +183,8 @@ net_printf_error(THD *thd, uint errcode, ...)
if (thd->spcont && thd->spcont->find_handler(errcode,
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
+ if (! thd->spcont->found_handler_here())
+ thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_VOID_RETURN;
}
thd->query_error= 1; // needed to catch query errors during replication
diff --git a/sql/records.cc b/sql/records.cc
index b3610cf1bbf..4958e39a5a0 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -28,8 +28,50 @@ static int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(THD *thd, READ_RECORD *info);
static int rr_cmp(uchar *a,uchar *b);
+static int rr_index_first(READ_RECORD *info);
+static int rr_index(READ_RECORD *info);
+
+
+/*
+ Initialize READ_RECORD structure to perform full index scan
+
+ SYNOPSIS
+ init_read_record_idx()
+ info READ_RECORD structure to initialize.
+ thd Thread handle
+ table Table to be accessed
+ print_error If true, call table->file->print_error() if an error
+ occurs (except for end-of-records error)
+ idx index to scan
+
+ DESCRIPTION
+ Initialize READ_RECORD structure to perform full index scan (in forward
+ direction) using read_record.read_record() interface.
+
+ This function has been added at late stage and is used only by
+ UPDATE/DELETE. Other statements perform index scans using
+ join_read_first/next functions.
+*/
+
+void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
+ bool print_error, uint idx)
+{
+ bzero((char*) info,sizeof(*info));
+ info->table= table;
+ info->file= table->file;
+ info->record= table->record[0];
+ info->print_error= print_error;
+
+ table->status=0; /* And it's always found */
+ if (!table->file->inited)
+ {
+ table->file->ha_index_init(idx);
+ table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
+ }
+ /* read_record will be changed to rr_index in rr_index_first */
+ info->read_record= rr_index_first;
+}
- /* init struct for read with info->read_record */
/*
init_read_record is used to scan by using a number of different methods.
@@ -225,6 +267,21 @@ void end_read_record(READ_RECORD *info)
}
}
+static int rr_handle_error(READ_RECORD *info, int error)
+{
+ if (error == HA_ERR_END_OF_FILE)
+ error= -1;
+ else
+ {
+ if (info->print_error)
+ info->table->file->print_error(error, MYF(0));
+ if (error < 0) // Fix negative BDB errno
+ error= 1;
+ }
+ return error;
+}
+
+
/* Read a record from head-database */
static int rr_quick(READ_RECORD *info)
@@ -239,15 +296,7 @@ static int rr_quick(READ_RECORD *info)
}
if (tmp != HA_ERR_RECORD_DELETED)
{
- if (tmp == HA_ERR_END_OF_FILE)
- tmp= -1;
- else
- {
- if (info->print_error)
- info->file->print_error(tmp,MYF(0));
- if (tmp < 0) // Fix negative BDB errno
- tmp=1;
- }
+ tmp= rr_handle_error(info, tmp);
break;
}
}
@@ -255,6 +304,57 @@ static int rr_quick(READ_RECORD *info)
}
+/*
+ Reads first row in an index scan
+
+ SYNOPSIS
+ rr_index_first()
+ info Scan info
+
+ RETURN
+ 0 Ok
+ -1 End of records
+ 1 Error
+*/
+
+
+static int rr_index_first(READ_RECORD *info)
+{
+ int tmp= info->file->index_first(info->record);
+ info->read_record= rr_index;
+ if (tmp)
+ tmp= rr_handle_error(info, tmp);
+ return tmp;
+}
+
+
+/*
+ Reads index sequentially after first row
+
+ SYNOPSIS
+ rr_index()
+ info Scan info
+
+ DESCRIPTION
+ Read the next index record (in forward direction) and translate return
+ value.
+
+ RETURN
+ 0 Ok
+ -1 End of records
+ 1 Error
+*/
+
+
+static int rr_index(READ_RECORD *info)
+{
+ int tmp= info->file->index_next(info->record);
+ if (tmp)
+ tmp= rr_handle_error(info, tmp);
+ return tmp;
+}
+
+
static int rr_sequential(READ_RECORD *info)
{
int tmp;
@@ -265,17 +365,13 @@ static int rr_sequential(READ_RECORD *info)
info->thd->send_kill_message();
return 1;
}
+ /*
+ rnd_next can return RECORD_DELETED for MyISAM when one thread is
+ reading and another deleting without locks.
+ */
if (tmp != HA_ERR_RECORD_DELETED)
{
- if (tmp == HA_ERR_END_OF_FILE)
- tmp= -1;
- else
- {
- if (info->print_error)
- info->table->file->print_error(tmp,MYF(0));
- if (tmp < 0) // Fix negative BDB errno
- tmp=1;
- }
+ tmp= rr_handle_error(info, tmp);
break;
}
}
@@ -286,23 +382,18 @@ static int rr_sequential(READ_RECORD *info)
static int rr_from_tempfile(READ_RECORD *info)
{
int tmp;
-tryNext:
- if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
- return -1; /* End of file */
- if ((tmp=info->file->rnd_pos(info->record,info->ref_pos)))
+ for (;;)
{
- if (tmp == HA_ERR_END_OF_FILE)
- tmp= -1;
- else if (tmp == HA_ERR_RECORD_DELETED ||
- (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
- goto tryNext;
- else
- {
- if (info->print_error)
- info->file->print_error(tmp,MYF(0));
- if (tmp < 0) // Fix negative BDB errno
- tmp=1;
- }
+ if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
+ return -1; /* End of file */
+ if (!(tmp=info->file->rnd_pos(info->record,info->ref_pos)))
+ break;
+ /* The following is extremely unlikely to happen */
+ if (tmp == HA_ERR_RECORD_DELETED ||
+ (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
+ continue;
+ tmp= rr_handle_error(info, tmp);
+ break;
}
return tmp;
} /* rr_from_tempfile */
@@ -340,26 +431,23 @@ static int rr_from_pointers(READ_RECORD *info)
{
int tmp;
byte *cache_pos;
-tryNext:
- if (info->cache_pos == info->cache_end)
- return -1; /* End of file */
- cache_pos=info->cache_pos;
- info->cache_pos+=info->ref_length;
- if ((tmp=info->file->rnd_pos(info->record,cache_pos)))
+ for (;;)
{
- if (tmp == HA_ERR_END_OF_FILE)
- tmp= -1;
- else if (tmp == HA_ERR_RECORD_DELETED ||
- (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
- goto tryNext;
- else
- {
- if (info->print_error)
- info->file->print_error(tmp,MYF(0));
- if (tmp < 0) // Fix negative BDB errno
- tmp=1;
- }
+ if (info->cache_pos == info->cache_end)
+ return -1; /* End of file */
+ cache_pos= info->cache_pos;
+ info->cache_pos+= info->ref_length;
+
+ if (!(tmp=info->file->rnd_pos(info->record,cache_pos)))
+ break;
+
+ /* The following is extremely unlikely to happen */
+ if (tmp == HA_ERR_RECORD_DELETED ||
+ (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
+ continue;
+ tmp= rr_handle_error(info, tmp);
+ break;
}
return tmp;
}
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 35035a8b5a5..823930121fe 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -68,7 +68,6 @@ static int init_failsafe_rpl_thread(THD* thd)
*/
thd->system_thread = thd->bootstrap = 1;
thd->security_ctx->skip_grants();
- thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
thd->max_client_packet_length=thd->net.max_packet;
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 3aabc4e5b1f..5c2cc77d66a 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5210,8 +5210,7 @@ ER_WARN_VIEW_WITHOUT_KEY
rus "ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÙÈ(ÏÊ) × ÎÅÍ ÔÁÂÌÉÃ(Ù)"
ukr "View, ÝÏ ÏÎÏ×ÌÀÅÔØÓÑ, ΊͦÓÔÉÔØ ÐÏ×ÎÏÇÏ ËÌÀÞÁ ÔÁÂÌÉæ(Ø), ÝÏ ×ÉËÏÒ¦ÓÔÁÎÁ × ÎØÀÏÍÕ"
ER_VIEW_INVALID
- eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s)"
- rus "View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ ÉÌÉ ÆÕÎËÃÉÉ"
+ eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
ER_SP_NO_DROP_SP
eng "Can't drop or alter a %s from within another stored routine"
ER_SP_GOTO_IN_HNDLR
@@ -5420,6 +5419,8 @@ ER_ROW_IS_REFERENCED_2 23000
eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
ER_NO_REFERENCED_ROW_2 23000
eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
+ER_SP_BAD_VAR_SHADOW 42000
+ eng "Variable '%-.64s' must be quoted with `...`, or renamed"
ER_PARTITION_REQUIRES_VALUES_ERROR
eng "%s PARTITIONING requires definition of VALUES %s for each partition"
swe "%s PARTITIONering kräver definition av VALUES %s för varje partition"
diff --git a/sql/slave.cc b/sql/slave.cc
index 279be4d9c8c..2ae51e37930 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -564,6 +564,20 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
rli->slave_skip_counter=0;
pthread_mutex_lock(&rli->data_lock);
+
+ /*
+ we close the relay log fd possibly left open by the slave SQL thread,
+ to be able to delete it; the relay log fd possibly left open by the slave
+ I/O thread will be closed naturally in reset_logs() by the
+ close(LOG_CLOSE_TO_BE_OPENED) call
+ */
+ if (rli->cur_log_fd >= 0)
+ {
+ end_io_cache(&rli->cache_buf);
+ my_close(rli->cur_log_fd, MYF(MY_WME));
+ rli->cur_log_fd= -1;
+ }
+
if (rli->relay_log.reset_logs(thd))
{
*errmsg = "Failed during log reset";
@@ -1393,9 +1407,26 @@ static int init_relay_log_info(RELAY_LOG_INFO* rli,
{
char buf[FN_REFLEN];
const char *ln;
+ static bool name_warning_sent= 0;
ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
1, buf);
-
+ /* We send the warning only at startup, not after every RESET SLAVE */
+ if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent)
+ {
+ /*
+ User didn't give us info to name the relay log index file.
+ Picking `hostname`-relay-bin.index like we do, causes replication to
+ fail if this slave's hostname is changed later. So, we would like to
+ instead require a name. But as we don't want to break many existing
+ setups, we only give warning, not error.
+ */
+ sql_print_warning("Neither --relay-log nor --relay-log-index were used;"
+ " so replication "
+ "may break when this MySQL server acts as a "
+ "slave and has his hostname changed!! Please "
+ "use '--relay-log=%s' to avoid this problem.", ln);
+ name_warning_sent= 1;
+ }
/*
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
@@ -1619,6 +1650,55 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli)
}
+/*
+ Builds a Rotate from the ignored events' info and writes it to relay log.
+
+ SYNOPSIS
+ write_ignored_events_info_to_relay_log()
+ thd pointer to I/O thread's thd
+ mi
+
+ DESCRIPTION
+ Slave I/O thread, going to die, must leave a durable trace of the
+ ignored events' end position for the use of the slave SQL thread, by
+ calling this function. Only that thread can call it (see assertion).
+ */
+static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
+{
+ RELAY_LOG_INFO *rli= &mi->rli;
+ pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
+ DBUG_ASSERT(thd == mi->io_thd);
+ pthread_mutex_lock(log_lock);
+ if (rli->ign_master_log_name_end[0])
+ {
+ DBUG_PRINT("info",("writing a Rotate event to track down ignored events"));
+ Rotate_log_event *ev= new Rotate_log_event(thd, rli->ign_master_log_name_end,
+ 0, rli->ign_master_log_pos_end,
+ Rotate_log_event::DUP_NAME);
+ rli->ign_master_log_name_end[0]= 0;
+ /* can unlock before writing as slave SQL thd will soon see our Rotate */
+ pthread_mutex_unlock(log_lock);
+ if (likely((bool)ev))
+ {
+ ev->server_id= 0; // don't be ignored by slave SQL thread
+ if (unlikely(rli->relay_log.append(ev)))
+ sql_print_error("Slave I/O thread failed to write a Rotate event"
+ " to the relay log, "
+ "SHOW SLAVE STATUS may be inaccurate");
+ rli->relay_log.harvest_bytes_written(&rli->log_space_total);
+ flush_master_info(mi, 1);
+ delete ev;
+ }
+ else
+ sql_print_error("Slave I/O thread failed to create a Rotate event"
+ " (out of memory?), "
+ "SHOW SLAVE STATUS may be inaccurate");
+ }
+ else
+ pthread_mutex_unlock(log_lock);
+}
+
+
void init_master_info_with_options(MASTER_INFO* mi)
{
mi->master_log_name[0] = 0;
@@ -2168,7 +2248,7 @@ st_relay_log_info::st_relay_log_info()
{
group_relay_log_name[0]= event_relay_log_name[0]=
group_master_log_name[0]= 0;
- last_slave_error[0]=0; until_log_name[0]= 0;
+ last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0;
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
@@ -2371,7 +2451,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
else
pthread_cond_wait(&data_cond, &data_lock);
DBUG_PRINT("info",("Got signal of master update or timed out"));
- if (error == ETIMEDOUT)
+ if (error == ETIMEDOUT || error == ETIME)
{
error= -1;
break;
@@ -2427,7 +2507,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
thd->security_ctx->skip_grants();
- thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
thd->slave_thread = 1;
@@ -2761,12 +2840,20 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
wait for something for example inside of next_event().
*/
pthread_mutex_lock(&rli->data_lock);
-
+ /*
+ This tests if the position of the end of the last previous executed event
+ hits the UNTIL barrier.
+ We would prefer to test if the position of the start (or possibly) end of
+ the to-be-read event hits the UNTIL barrier, this is different if there
+ was an event ignored by the I/O thread just before (BUG#13861 to be
+ fixed).
+ */
if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE &&
rli->is_until_satisfied())
{
+ char buf[22];
sql_print_error("Slave SQL thread stopped because it reached its"
- " UNTIL position %ld", (long) rli->until_pos());
+ " UNTIL position %s", llstr(rli->until_pos(), buf));
/*
Setting abort_slave flag because we do not want additional message about
error in query execution to be printed.
@@ -2954,6 +3041,7 @@ pthread_handler_t handle_slave_io(void *arg)
THD *thd; // needs to be first for thread_stack
MYSQL *mysql;
MASTER_INFO *mi = (MASTER_INFO*)arg;
+ RELAY_LOG_INFO *rli= &mi->rli;
char llbuff[22];
uint retry_count;
@@ -3196,16 +3284,16 @@ reconnect done to recover from failed read");
char llbuf1[22], llbuf2[22];
DBUG_PRINT("info", ("log_space_limit=%s log_space_total=%s \
ignore_log_space_limit=%d",
- llstr(mi->rli.log_space_limit,llbuf1),
- llstr(mi->rli.log_space_total,llbuf2),
- (int) mi->rli.ignore_log_space_limit));
+ llstr(rli->log_space_limit,llbuf1),
+ llstr(rli->log_space_total,llbuf2),
+ (int) rli->ignore_log_space_limit));
}
#endif
- if (mi->rli.log_space_limit && mi->rli.log_space_limit <
- mi->rli.log_space_total &&
- !mi->rli.ignore_log_space_limit)
- if (wait_for_relay_log_space(&mi->rli))
+ if (rli->log_space_limit && rli->log_space_limit <
+ rli->log_space_total &&
+ !rli->ignore_log_space_limit)
+ if (wait_for_relay_log_space(rli))
{
sql_print_error("Slave I/O thread aborted while waiting for relay \
log space");
@@ -3236,10 +3324,12 @@ err:
mysql_close(mysql);
mi->mysql=0;
}
+ write_ignored_events_info_to_relay_log(thd, mi);
thd->proc_info = "Waiting for slave mutex on exit";
pthread_mutex_lock(&mi->run_lock);
mi->slave_running = 0;
mi->io_thd = 0;
+
/* Forget the relay log's format */
delete mi->rli.relay_log.description_event_for_queue;
mi->rli.relay_log.description_event_for_queue= 0;
@@ -3618,6 +3708,7 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
if (unlikely(!rev->is_valid()))
DBUG_RETURN(1);
+ /* Safe copy as 'rev' has been "sanitized" in Rotate_log_event's ctor */
memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1);
mi->master_log_pos= rev->pos;
DBUG_PRINT("info", ("master_log_pos: '%s' %d",
@@ -3868,6 +3959,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
int error= 0;
ulong inc_pos;
RELAY_LOG_INFO *rli= &mi->rli;
+ pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
DBUG_ENTER("queue_event");
if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
@@ -3876,11 +3968,6 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
pthread_mutex_lock(&mi->data_lock);
- /*
- TODO: figure out if other events in addition to Rotate
- require special processing.
- Guilhem 2003-06 : I don't think so.
- */
switch (buf[EVENT_TYPE_OFFSET]) {
case STOP_EVENT:
/*
@@ -3965,14 +4052,21 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
direct master (an unsupported, useless setup!).
*/
+ pthread_mutex_lock(log_lock);
+
if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
!replicate_same_server_id)
{
/*
Do not write it to the relay log.
- We still want to increment, so that we won't re-read this event from the
- master if the slave IO thread is now stopped/restarted (more efficient if
- the events we are ignoring are big LOAD DATA INFILE).
+ a) We still want to increment mi->master_log_pos, so that we won't
+ re-read this event from the master if the slave IO thread is now
+ stopped/restarted (more efficient if the events we are ignoring are big
+ LOAD DATA INFILE).
+ b) We want to record that we are skipping events, for the information of
+ the slave SQL thread, otherwise that thread may let
+ rli->group_relay_log_pos stay too small if the last binlog's event is
+ ignored.
But events which were generated by this slave and which do not exist in
the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment
mi->master_log_pos.
@@ -3980,7 +4074,13 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT &&
buf[EVENT_TYPE_OFFSET]!=STOP_EVENT)
+ {
mi->master_log_pos+= inc_pos;
+ memcpy(rli->ign_master_log_name_end, mi->master_log_name, FN_REFLEN);
+ DBUG_ASSERT(rli->ign_master_log_name_end[0]);
+ rli->ign_master_log_pos_end= mi->master_log_pos;
+ }
+ rli->relay_log.signal_update(); // the slave SQL thread needs to re-check
DBUG_PRINT("info", ("master_log_pos: %d, event originating from the same server, ignored", (ulong) mi->master_log_pos));
}
else
@@ -3993,8 +4093,11 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
}
else
- error=3;
+ error= 3;
+ rli->ign_master_log_name_end[0]= 0; // last event is not ignored
}
+ pthread_mutex_unlock(log_lock);
+
err:
pthread_mutex_unlock(&mi->data_lock);
@@ -4377,7 +4480,28 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
time_t save_timestamp= rli->last_master_timestamp;
rli->last_master_timestamp= 0;
- DBUG_ASSERT(rli->relay_log.get_open_count() == rli->cur_log_old_open_count);
+ DBUG_ASSERT(rli->relay_log.get_open_count() ==
+ rli->cur_log_old_open_count);
+
+ if (rli->ign_master_log_name_end[0])
+ {
+ /* We generate and return a Rotate, to make our positions advance */
+ DBUG_PRINT("info",("seeing an ignored end segment"));
+ ev= new Rotate_log_event(thd, rli->ign_master_log_name_end,
+ 0, rli->ign_master_log_pos_end,
+ Rotate_log_event::DUP_NAME);
+ rli->ign_master_log_name_end[0]= 0;
+ pthread_mutex_unlock(log_lock);
+ if (unlikely(!ev))
+ {
+ errmsg= "Slave SQL thread failed to create a Rotate event "
+ "(out of memory?), SHOW SLAVE STATUS may be inaccurate";
+ goto err;
+ }
+ ev->server_id= 0; // don't be ignored by slave SQL thread
+ DBUG_RETURN(ev);
+ }
+
/*
We can, and should release data_lock while we are waiting for
update. If we do not, show slave status will block
diff --git a/sql/slave.h b/sql/slave.h
index d99145cbe47..c994bfb2d34 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -304,6 +304,17 @@ typedef struct st_relay_log_info
*/
ulong trans_retries, retried_trans;
+ /*
+ If the end of the hot relay log is made of master's events ignored by the
+ slave I/O thread, these two keep track of the coords (in the master's
+ binlog) of the last of these events seen by the slave I/O thread. If not,
+ ign_master_log_name_end[0] == 0.
+ As they are like a Rotate event read/written from/to the relay log, they
+ are both protected by rli->relay_log.LOCK_log.
+ */
+ char ign_master_log_name_end[FN_REFLEN];
+ ulonglong ign_master_log_pos_end;
+
st_relay_log_info();
~st_relay_log_info();
diff --git a/sql/sp.cc b/sql/sp.cc
index 18d94a85884..b385c6457a5 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -208,7 +208,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
{
byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
DBUG_ENTER("db_find_routine_aux");
- DBUG_PRINT("enter", ("type: %d name: %*s",
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
/*
@@ -275,7 +275,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
ulong sql_mode;
Open_tables_state open_tables_state_backup;
DBUG_ENTER("db_find_routine");
- DBUG_PRINT("enter", ("type: %d name: %*s",
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
*sphp= 0; // In case of errors
@@ -479,7 +479,8 @@ db_create_routine(THD *thd, int type, sp_head *sp)
char olddb[128];
bool dbchanged;
DBUG_ENTER("db_create_routine");
- DBUG_PRINT("enter", ("type: %d name: %*s",type,sp->m_name.length,sp->m_name.str));
+ DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length,
+ sp->m_name.str));
dbchanged= FALSE;
if ((ret= sp_use_new_db(thd, sp->m_db.str, olddb, sizeof(olddb),
@@ -606,7 +607,7 @@ db_drop_routine(THD *thd, int type, sp_name *name)
TABLE *table;
int ret;
DBUG_ENTER("db_drop_routine");
- DBUG_PRINT("enter", ("type: %d name: %*s",
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
if (!(table= open_proc_table_for_update(thd)))
@@ -628,7 +629,7 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
int ret;
bool opened;
DBUG_ENTER("db_update_routine");
- DBUG_PRINT("enter", ("type: %d name: %*s",
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
if (!(table= open_proc_table_for_update(thd)))
@@ -922,7 +923,7 @@ sp_find_procedure(THD *thd, sp_name *name, bool cache_only)
{
sp_head *sp;
DBUG_ENTER("sp_find_procedure");
- DBUG_PRINT("enter", ("name: %*s.%*s",
+ DBUG_PRINT("enter", ("name: %.*s.%.*s",
name->m_db.length, name->m_db.str,
name->m_name.length, name->m_name.str));
@@ -980,7 +981,7 @@ sp_create_procedure(THD *thd, sp_head *sp)
{
int ret;
DBUG_ENTER("sp_create_procedure");
- DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str));
ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp);
DBUG_RETURN(ret);
@@ -992,7 +993,7 @@ sp_drop_procedure(THD *thd, sp_name *name)
{
int ret;
DBUG_ENTER("sp_drop_procedure");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
if (!ret)
@@ -1006,7 +1007,7 @@ sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
{
int ret;
DBUG_ENTER("sp_update_procedure");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
if (!ret)
@@ -1020,7 +1021,7 @@ sp_show_create_procedure(THD *thd, sp_name *name)
{
sp_head *sp;
DBUG_ENTER("sp_show_create_procedure");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
if ((sp= sp_find_procedure(thd, name)))
{
@@ -1072,7 +1073,7 @@ sp_find_function(THD *thd, sp_name *name, bool cache_only)
{
sp_head *sp;
DBUG_ENTER("sp_find_function");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
!cache_only)
@@ -1089,7 +1090,7 @@ sp_create_function(THD *thd, sp_head *sp)
{
int ret;
DBUG_ENTER("sp_create_function");
- DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str));
ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp);
DBUG_RETURN(ret);
@@ -1101,7 +1102,7 @@ sp_drop_function(THD *thd, sp_name *name)
{
int ret;
DBUG_ENTER("sp_drop_function");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
if (!ret)
@@ -1115,7 +1116,7 @@ sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
{
int ret;
DBUG_ENTER("sp_update_procedure");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
if (!ret)
@@ -1129,7 +1130,7 @@ sp_show_create_function(THD *thd, sp_name *name)
{
sp_head *sp;
DBUG_ENTER("sp_show_create_function");
- DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
if ((sp= sp_find_function(thd, name)))
{
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index 495f969eeac..fea6a67f32c 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -132,7 +132,7 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp)
return; // End of memory error
c->version= Cversion; // No need to lock when reading long variable
}
- DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length,
+ DBUG_PRINT("info",("sp_cache: inserting: %.*s", sp->m_qname.length,
sp->m_qname.str));
c->insert(sp);
*cp= c; // Update *cp if it was NULL
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 671acbc2a0c..abc66ce0b21 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -280,7 +280,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
DBUG_PRINT("info", ("STRING_RESULT: null"));
goto return_null_item;
}
- DBUG_PRINT("info",("STRING_RESULT: %*s",
+ DBUG_PRINT("info",("STRING_RESULT: %.*s",
s->length(), s->c_ptr_quick()));
/*
Reuse mechanism in sp_eval_func_item() is only employed for assignments
@@ -293,6 +293,22 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
if (it == reuse)
DBUG_RETURN(it);
+ /*
+ For some functions, 's' is now pointing to an argument of the
+ function, which might be a local variable that is to be reused.
+ In this case, new(reuse, &rsize) below will call the destructor
+ and 's' ends up pointing to freed memory.
+ A somewhat ugly fix is to simply copy the string to our local one
+ (which is unused by most functions anyway), but only if 's' is
+ pointing somewhere else than to 'tmp' or 'it->str_value'.
+ */
+ if (reuse && s != &tmp && s != &it->str_value)
+ {
+ if (tmp.copy((const String)(*s)))
+ DBUG_RETURN(NULL);
+ s= &tmp;
+ }
+
CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
Item_string(it->collation.collation),
use_callers_arena, &backup_arena);
@@ -323,7 +339,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
return_null_item:
CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
- use_callers_arena, &backup_arena);
+ use_callers_arena, &backup_arena);
end:
it->rsize= rsize;
@@ -354,7 +370,7 @@ sp_name::init_qname(THD *thd)
return;
m_qname.length= m_sroutines_key.length - 1;
m_qname.str= m_sroutines_key.str + 1;
- sprintf(m_qname.str, "%*s.%*s",
+ sprintf(m_qname.str, "%.*s.%.*s",
m_db.length, (m_db.length ? m_db.str : ""),
m_name.length, m_name.str);
}
@@ -794,6 +810,7 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
splocal < sp_vars_uses.back(); splocal++)
{
Item *val;
+ (*splocal)->thd= thd; // fix_fields() is not yet done
/* append the text between sp ref occurences */
res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length;
@@ -1051,8 +1068,10 @@ int sp_head::execute(THD *thd)
original thd->db will then have been freed */
if (dbchanged)
{
+ /* No access check when changing back to where we came from.
+ (It would generate an error from mysql_change_db() when olddb=="") */
if (! thd->killed)
- ret= mysql_change_db(thd, olddb, 0);
+ ret= mysql_change_db(thd, olddb, 1);
}
m_flags&= ~IS_INVOKED;
DBUG_RETURN(ret);
@@ -1110,7 +1129,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
DBUG_RETURN(-1);
// QQ Should have some error checking here? (types, etc...)
- if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
+ if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
goto end;
for (i= 0 ; i < argcount ; i++)
{
@@ -1254,7 +1273,7 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
save_spcont= octx= thd->spcont;
if (! octx)
{ // Create a temporary old context
- if (!(octx= new sp_rcontext(csize, hmax, cmax)))
+ if (!(octx= new sp_rcontext(octx, csize, hmax, cmax)))
DBUG_RETURN(-1);
thd->spcont= octx;
@@ -1262,7 +1281,7 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont->callers_arena= thd;
}
- if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
+ if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
{
thd->spcont= save_spcont;
DBUG_RETURN(-1);
@@ -2390,7 +2409,10 @@ sp_instr_hreturn::print(String *str)
str->append("hreturn ");
str->qs_append(m_frame);
if (m_dest)
+ {
+ str->append(' ');
str->qs_append(m_dest);
+ }
}
@@ -2650,9 +2672,24 @@ sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup)
sp->m_definer_host.str,
sp->m_db.str))
{
+#ifdef NOT_YET_REPLICATION_SAFE
+ /*
+ Until we don't properly replicate information about stored routine
+ definer with stored routine creation statement all stored routines
+ on slave are created under ''@'' definer. Therefore we won't be able
+ to run any routine which was replicated from master on slave server
+ if we emit error here. This will cause big problems for users
+ who use slave for fail-over. So until we fully implement WL#2897
+ "Complete definer support in the stored routines" we run suid
+ stored routines for which we were unable to find definer under
+ invoker security context.
+ */
my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str,
sp->m_definer_host.str);
return TRUE;
+#else
+ return FALSE;
+#endif
}
*backup= thd->security_ctx;
thd->security_ctx= &sp->m_security_ctx;
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 252bd7e5cab..ccb38358049 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -29,9 +29,9 @@
#include "sp_rcontext.h"
#include "sp_pcontext.h"
-sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
+sp_rcontext::sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax)
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
- m_ihsp(0), m_hfound(-1), m_ccount(0)
+ m_ihsp(0), m_hfound(-1), m_ccount(0), m_prev_ctx(prev)
{
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
@@ -116,7 +116,11 @@ sp_rcontext::find_handler(uint sql_errno,
}
}
if (found < 0)
+ {
+ if (m_prev_ctx)
+ return m_prev_ctx->find_handler(sql_errno, level);
return FALSE;
+ }
m_hfound= found;
return TRUE;
}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 22fa4f6e865..cae5c5467c9 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -66,7 +66,7 @@ class sp_rcontext : public Sql_alloc
*/
Query_arena *callers_arena;
- sp_rcontext(uint fsize, uint hmax, uint cmax);
+ sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax);
~sp_rcontext()
{
@@ -149,6 +149,13 @@ class sp_rcontext : public Sql_alloc
return m_handler[m_hfound].type;
}
+ // Returns true if we found a handler in this context
+ inline bool
+ found_handler_here()
+ {
+ return (m_hfound >= 0);
+ }
+
// Clears the handler find state
inline void
clear_handler()
@@ -226,6 +233,8 @@ private:
sp_cursor **m_cstack;
uint m_ccount;
+ sp_rcontext *m_prev_ctx; // Previous context (NULL if none)
+
}; // class sp_rcontext : public Sql_alloc
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 176f1f2fbfe..5af1bec45ca 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -121,24 +121,21 @@ Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
return 0;
}
-Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
- const char *data, uint32 data_len)
+
+Geometry *Geometry::construct(Geometry_buffer *buffer,
+ const char *data, uint32 data_len)
{
uint32 geom_type;
Geometry *result;
+ char byte_order;
- if (data_len < 1 + 4)
+ if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4)
return NULL;
- data++;
- /*
- FIXME: check byte ordering
- Also check if we could replace this with one byte
- */
- geom_type= uint4korr(data);
- data+= 4;
+ byte_order= data[SRID_SIZE];
+ geom_type= uint4korr(data + SRID_SIZE + 1);
if (!(result= create_by_typeid(buffer, (int) geom_type)))
return NULL;
- result->m_data= data;
+ result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
result->m_data_end= data + data_len;
return result;
}
@@ -170,13 +167,71 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
return NULL;
if (init_stream)
{
- result->init_from_wkb(wkt->ptr(), wkt->length());
+ result->set_data_ptr(wkt->ptr(), wkt->length());
result->shift_wkb_header();
}
return result;
}
+static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
+{
+ double res;
+ if (bo != Geometry::wkb_xdr)
+ float8get(res, ptr);
+ else
+ {
+ char inv_array[8];
+ inv_array[0]= ptr[7];
+ inv_array[1]= ptr[6];
+ inv_array[2]= ptr[5];
+ inv_array[3]= ptr[4];
+ inv_array[4]= ptr[3];
+ inv_array[5]= ptr[2];
+ inv_array[6]= ptr[1];
+ inv_array[7]= ptr[0];
+ float8get(res, inv_array);
+ }
+ return res;
+}
+
+
+static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
+{
+ if (bo != Geometry::wkb_xdr)
+ return uint4korr(ptr);
+ /* else */
+ {
+ char inv_array[4];
+ inv_array[0]= ptr[3];
+ inv_array[1]= ptr[2];
+ inv_array[2]= ptr[1];
+ inv_array[3]= ptr[0];
+ return uint4korr(inv_array);
+ }
+}
+
+
+int Geometry::create_from_wkb(Geometry_buffer *buffer,
+ const char *wkb, uint32 len, String *res)
+{
+ uint32 geom_type;
+ Geometry *geom;
+
+ if (len < WKB_HEADER_SIZE)
+ return 1;
+ geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
+ if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
+ res->reserve(WKB_HEADER_SIZE, 512))
+ return 1;
+
+ res->q_append((char) wkb_ndr);
+ res->q_append(geom_type);
+ return geom->init_from_wkb(wkb+WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
+ (wkbByteOrder) wkb[0], res);
+}
+
+
bool Geometry::envelope(String *result) const
{
MBR mbr;
@@ -346,6 +401,20 @@ bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_point::init_from_wkb(const char *wkb, uint len,
+ wkbByteOrder bo, String *res)
+{
+ double x, y;
+ if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
+ return 0;
+ x= wkb_get_double(wkb, bo);
+ y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
+ res->q_append(x);
+ res->q_append(y);
+ return POINT_DATA_SIZE;
+}
+
+
bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
{
double x, y;
@@ -415,6 +484,33 @@ bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
+ wkbByteOrder bo, String *res)
+{
+ uint32 n_points, proper_length;
+ const char *wkb_end;
+ Gis_point p;
+
+ if (len < 4)
+ return 0;
+ n_points= wkb_get_uint(wkb, bo);
+ proper_length= 4 + n_points * POINT_DATA_SIZE;
+
+ if (len < proper_length || res->reserve(proper_length))
+ return 0;
+
+ res->q_append(n_points);
+ wkb_end= wkb + proper_length;
+ for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
+ {
+ if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
+ return 0;
+ }
+
+ return proper_length;
+}
+
+
bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
{
uint32 n_points;
@@ -594,7 +690,7 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
trs->check_next_symbol(')'))
return 1;
- ls.init_from_wkb(wkb->ptr()+ls_pos, wkb->length()-ls_pos);
+ ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
if (ls.is_closed(&closed) || !closed)
{
trs->set_error_msg("POLYGON's linear ring isn't closed");
@@ -609,6 +705,43 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
+ String *res)
+{
+ uint32 n_linear_rings;
+ const char *wkb_orig= wkb;
+
+ if (len < 4)
+ return 0;
+
+ n_linear_rings= wkb_get_uint(wkb, bo);
+ if (res->reserve(4, 512))
+ return 0;
+ wkb+= 4;
+ len-= 4;
+ res->q_append(n_linear_rings);
+
+ while (n_linear_rings--)
+ {
+ Gis_line_string ls;
+ uint32 ls_pos= res->length();
+ int ls_len;
+ int closed;
+
+ if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
+ return 0;
+
+ ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
+
+ if (ls.is_closed(&closed) || !closed)
+ return 0;
+ wkb+= ls_len;
+ }
+
+ return (uint) (wkb - wkb_orig);
+}
+
+
bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
{
uint32 n_linear_rings;
@@ -897,6 +1030,36 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
+ String *res)
+{
+ uint32 n_points;
+ uint proper_size;
+ Gis_point p;
+ const char *wkb_end;
+
+ if (len < 4)
+ return 0;
+ n_points= wkb_get_uint(wkb, bo);
+ proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
+
+ if (len < proper_size || res->reserve(proper_size))
+ return 0;
+
+ res->q_append(n_points);
+ wkb_end= wkb + proper_size;
+ for (wkb+=4; wkb < wkb_end; wkb+= (WKB_HEADER_SIZE + POINT_DATA_SIZE))
+ {
+ res->q_append((char)wkb_ndr);
+ res->q_append((uint32)wkb_point);
+ if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
+ POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
+ return 0;
+ }
+ return proper_size;
+}
+
+
bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
{
uint32 n_points;
@@ -1006,6 +1169,44 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
+ wkbByteOrder bo, String *res)
+{
+ uint32 n_line_strings;
+ const char *wkb_orig= wkb;
+
+ if (len < 4)
+ return 0;
+ n_line_strings= wkb_get_uint(wkb, bo);
+
+ if (res->reserve(4, 512))
+ return 0;
+ res->q_append(n_line_strings);
+
+ wkb+= 4;
+ while (n_line_strings--)
+ {
+ Gis_line_string ls;
+ int ls_len;
+
+ if ((len < WKB_HEADER_SIZE) ||
+ res->reserve(WKB_HEADER_SIZE, 512))
+ return 0;
+
+ res->q_append((char) wkb_ndr);
+ res->q_append((uint32) wkb_linestring);
+
+ if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
+ (wkbByteOrder) wkb[0], res)))
+ return 0;
+ ls_len+= WKB_HEADER_SIZE;;
+ wkb+= ls_len;
+ len-= ls_len;
+ }
+ return (uint) (wkb - wkb_orig);
+}
+
+
bool Gis_multi_line_string::get_data_as_wkt(String *txt,
const char **end) const
{
@@ -1111,7 +1312,7 @@ int Gis_multi_line_string::length(double *len) const
double ls_len;
Gis_line_string ls;
data+= WKB_HEADER_SIZE;
- ls.init_from_wkb(data, (uint32) (m_data_end - data));
+ ls.set_data_ptr(data, (uint32) (m_data_end - data));
if (ls.length(&ls_len))
return 1;
*len+= ls_len;
@@ -1140,7 +1341,7 @@ int Gis_multi_line_string::is_closed(int *closed) const
Gis_line_string ls;
if (no_data(data, 0))
return 1;
- ls.init_from_wkb(data, (uint32) (m_data_end - data));
+ ls.set_data_ptr(data, (uint32) (m_data_end - data));
if (ls.is_closed(closed))
return 1;
if (!*closed)
@@ -1222,6 +1423,43 @@ bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
+ wkbByteOrder bo, String *res)
+{
+ uint32 n_poly;
+ const char *wkb_orig= wkb;
+
+ if (len < 4)
+ return 0;
+ n_poly= wkb_get_uint(wkb, bo);
+
+ if (res->reserve(4, 512))
+ return 0;
+ res->q_append(n_poly);
+
+ wkb+=4;
+ while (n_poly--)
+ {
+ Gis_polygon p;
+ int p_len;
+
+ if (len < WKB_HEADER_SIZE ||
+ res->reserve(WKB_HEADER_SIZE, 512))
+ return 0;
+ res->q_append((char) wkb_ndr);
+ res->q_append((uint32) wkb_polygon);
+
+ if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
+ (wkbByteOrder) wkb[0], res)))
+ return 0;
+ p_len+= WKB_HEADER_SIZE;
+ wkb+= p_len;
+ len-= p_len;
+ }
+ return (uint) (wkb - wkb_orig);
+}
+
+
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
{
uint32 n_polygons;
@@ -1358,7 +1596,7 @@ int Gis_multi_polygon::area(double *ar, const char **end_of_data) const
Gis_polygon p;
data+= WKB_HEADER_SIZE;
- p.init_from_wkb(data, (uint32) (m_data_end - data));
+ p.set_data_ptr(data, (uint32) (m_data_end - data));
if (p.area(&p_area, &data))
return 1;
result+= p_area;
@@ -1390,7 +1628,7 @@ int Gis_multi_polygon::centroid(String *result) const
while (n_polygons--)
{
data+= WKB_HEADER_SIZE;
- p.init_from_wkb(data, (uint32) (m_data_end - data));
+ p.set_data_ptr(data, (uint32) (m_data_end - data));
if (p.area(&cur_area, &data) ||
p.centroid_xy(&cur_cx, &cur_cy))
return 1;
@@ -1444,7 +1682,7 @@ uint32 Gis_geometry_collection::get_data_size() const
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return GET_SIZE_ERROR;
- geom->init_from_wkb(data, (uint) (m_data_end - data));
+ geom->set_data_ptr(data, (uint) (m_data_end - data));
if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
return GET_SIZE_ERROR;
data+= object_size;
@@ -1484,6 +1722,48 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
+uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
+ wkbByteOrder bo, String *res)
+{
+ uint32 n_geom;
+ const char *wkb_orig= wkb;
+
+ if (len < 4)
+ return 0;
+ n_geom= wkb_get_uint(wkb, bo);
+
+ if (res->reserve(4, 512))
+ return 0;
+ res->q_append(n_geom);
+
+ wkb+= 4;
+ while (n_geom--)
+ {
+ Geometry_buffer buffer;
+ Geometry *geom;
+ int g_len;
+ uint32 wkb_type;
+
+ if (len < WKB_HEADER_SIZE ||
+ res->reserve(WKB_HEADER_SIZE, 512))
+ return 0;
+
+ res->q_append((char) wkb_ndr);
+ wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
+ res->q_append(wkb_type);
+
+ if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
+ !(g_len= geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len,
+ (wkbByteOrder) wkb[0], res)))
+ return 0;
+ g_len+= WKB_HEADER_SIZE;
+ wkb+= g_len;
+ len-= g_len;
+ }
+ return (uint) (wkb - wkb_orig);
+}
+
+
bool Gis_geometry_collection::get_data_as_wkt(String *txt,
const char **end) const
{
@@ -1508,7 +1788,7 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt,
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
- geom->init_from_wkb(data, (uint) (m_data_end - data));
+ geom->set_data_ptr(data, (uint) (m_data_end - data));
if (geom->as_wkt(txt, &data))
return 1;
if (txt->append(",", 1, 512))
@@ -1543,7 +1823,7 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
- geom->init_from_wkb(data, (uint32) (m_data_end - data));
+ geom->set_data_ptr(data, (uint32) (m_data_end - data));
if (geom->get_mbr(mbr, &data))
return 1;
}
@@ -1584,7 +1864,7 @@ int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
- geom->init_from_wkb(data, (uint) (m_data_end - data));
+ geom->set_data_ptr(data, (uint) (m_data_end - data));
if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
return 1;
data+= length;
@@ -1637,7 +1917,7 @@ bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
- geom->init_from_wkb(data, (uint32) (m_data_end - data));
+ geom->set_data_ptr(data, (uint32) (m_data_end - data));
if (geom->dimension(&dim, &end_data))
return 1;
set_if_bigger(*res_dim, dim);
diff --git a/sql/spatial.h b/sql/spatial.h
index b5ea7d641d1..4253689c078 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -207,6 +207,10 @@ public:
virtual const Class_info *get_class_info() const=0;
virtual uint32 get_data_size() const=0;
virtual bool init_from_wkt(Gis_read_stream *trs, String *wkb)=0;
+
+ /* returns the length of the wkb that was read */
+ virtual uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
+ String *res)=0;
virtual bool get_data_as_wkt(String *txt, const char **end) const=0;
virtual bool get_mbr(MBR *mbr, const char **end) const=0;
virtual bool dimension(uint32 *dim, const char **end) const=0;
@@ -236,11 +240,13 @@ public:
return my_reinterpret_cast(Geometry *)(buffer);
}
- static Geometry *create_from_wkb(Geometry_buffer *buffer,
- const char *data, uint32 data_len);
+ static Geometry *construct(Geometry_buffer *buffer,
+ const char *data, uint32 data_len);
static Geometry *create_from_wkt(Geometry_buffer *buffer,
Gis_read_stream *trs, String *wkt,
bool init_stream=1);
+ static int create_from_wkb(Geometry_buffer *buffer,
+ const char *wkb, uint32 len, String *res);
int as_wkt(String *wkt, const char **end)
{
uint32 len= get_class_info()->m_name.length;
@@ -254,7 +260,7 @@ public:
return 0;
}
- inline void init_from_wkb(const char *data, uint32 data_len)
+ inline void set_data_ptr(const char *data, uint32 data_len)
{
m_data= data;
m_data_end= data + data_len;
@@ -298,6 +304,7 @@ class Gis_point: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
@@ -344,6 +351,7 @@ class Gis_line_string: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int length(double *len) const;
@@ -369,6 +377,7 @@ class Gis_polygon: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int area(double *ar, const char **end) const;
@@ -394,6 +403,7 @@ class Gis_multi_point: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
@@ -415,6 +425,7 @@ class Gis_multi_line_string: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
@@ -438,6 +449,7 @@ class Gis_multi_polygon: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
@@ -461,6 +473,7 @@ class Gis_geometry_collection: public Geometry
public:
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
+ uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7a87f01258a..c47507bdd27 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -193,6 +193,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
my_bool return_val= 1;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
+ int password_length;
DBUG_ENTER("acl_load");
grant_version++; /* Privileges updated */
@@ -249,7 +250,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
- if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ password_length= table->field[2]->field_length /
+ table->field[2]->charset()->mbmaxlen;
+ if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
sql_print_error("Fatal error: mysql.user table is damaged or in "
"unsupported 3.20 format.");
@@ -257,10 +260,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
}
DBUG_PRINT("info",("user table fields: %d, password length: %d",
- table->s->fields, table->field[2]->field_length));
+ table->s->fields, password_length));
pthread_mutex_lock(&LOCK_global_system_variables);
- if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
{
if (opt_secure_auth)
{
@@ -930,6 +933,9 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot_no_password");
+ DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
+ (host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
+ (user ? user : "(NULL)"), (db ? db : "(NULL)")));
sctx->user= user;
sctx->host= host;
sctx->ip= ip;
@@ -1486,6 +1492,11 @@ end:
bool is_acl_user(const char *host, const char *user)
{
bool res;
+
+ /* --skip-grants */
+ if (!initialized)
+ return TRUE;
+
VOID(pthread_mutex_lock(&acl_cache->lock));
res= find_acl_user(host, user, TRUE) != NULL;
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -3504,17 +3515,38 @@ end:
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_table, uint number, bool no_errors)
{
- TABLE_LIST *table;
+ TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
+ uint i;
DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0);
+ /*
+ Walk through the list of tables that belong to the query and save the
+ requested access (orig_want_privilege) to be able to use it when
+ checking access rights to the underlying tables of a view. Our grant
+ system gradually eliminates checked bits from want_privilege and thus
+ after all checks are done we can no longer use it.
+ The check that first_not_own_table is not reached is for the case when
+ the given table list refers to the list for prelocking (contains tables
+ of other queries). For simple queries first_not_own_table is 0.
+ */
+ for (i= 0, table= tables;
+ table != first_not_own_table && i < number;
+ table= table->next_global, i++)
+ {
+ /* Remove SHOW_VIEW_ACL, because it will be checked during making view */
+ table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+ }
+
want_access&= ~sctx->master_access;
if (!want_access)
DBUG_RETURN(0); // ok
rw_rdlock(&LOCK_grant);
- for (table= tables; table && number--; table= table->next_global)
+ for (table= tables;
+ table && number-- && table != first_not_own_table;
+ table= table->next_global)
{
GRANT_TABLE *grant_table;
if (!(~table->grant.privilege & want_access) ||
@@ -3524,8 +3556,16 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
It is subquery in the FROM clause. VIEW set table->derived after
table opening, but this function always called before table opening.
*/
- table->grant.want_privilege= 0;
- continue; // Already checked
+ if (!table->referencing_view)
+ {
+ /*
+ If it's a temporary table created for a subquery in the FROM
+ clause, or an INFORMATION_SCHEMA table, drop the request for
+ a privilege.
+ */
+ table->grant.want_privilege= 0;
+ }
+ continue;
}
if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
table->db, sctx->priv_user,
@@ -5834,24 +5874,37 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table)
{
Security_context *sctx= thd->security_ctx;
+ DBUG_ENTER("fill_effective_table_privileges");
+ DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', table: `%s`.`%s`",
+ sctx->priv_host, (sctx->ip ? sctx->ip : "(NULL)"),
+ (sctx->priv_user ? sctx->priv_user : "(NULL)"),
+ db, table));
/* --skip-grants */
if (!initialized)
{
+ DBUG_PRINT("info", ("skip grants"));
grant->privilege= ~NO_ACCESS; // everything is allowed
- return;
+ DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+ DBUG_VOID_RETURN;
}
/* global privileges */
grant->privilege= sctx->master_access;
if (!sctx->priv_user)
- return; // it is slave
+ {
+ DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+ DBUG_VOID_RETURN; // it is slave
+ }
/* db privileges */
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
if (!grant_option)
- return;
+ {
+ DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+ DBUG_VOID_RETURN;
+ }
/* table privileges */
if (grant->version != grant_version)
@@ -5868,6 +5921,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
{
grant->privilege|= grant->grant_table->privs;
}
+ DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+ DBUG_VOID_RETURN;
}
#else /* NO_EMBEDDED_ACCESS_CHECKS */
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 669f998cde5..e1f4b8f6076 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -466,7 +466,9 @@ void field_real::add()
void field_decimal::add()
{
+ /*TODO - remove rounding stuff after decimal_div returns proper frac */
my_decimal dec_buf, *dec= item->val_decimal(&dec_buf);
+ my_decimal rounded;
uint length;
TREE_ELEMENT *element;
@@ -476,6 +478,9 @@ void field_decimal::add()
return;
}
+ my_decimal_round(E_DEC_FATAL_ERROR, dec, item->decimals, FALSE,&rounded);
+ dec= &rounded;
+
length= my_decimal_string_length(dec);
if (decimal_is_zero(dec))
@@ -1021,10 +1026,16 @@ String *field_decimal::avg(String *s, ha_rows rows)
s->set((double) 0.0, 1,my_thd_charset);
return s;
}
- my_decimal num, avg_val;
+ my_decimal num, avg_val, rounded_avg;
+ int prec_increment= current_thd->variables.div_precincrement;
+
int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
- my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, 0);
- my_decimal2string(E_DEC_FATAL_ERROR, &avg_val, 0, 0, '0', s);
+ my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, prec_increment);
+ /* TODO remove this after decimal_div returns proper frac */
+ my_decimal_round(E_DEC_FATAL_ERROR, &avg_val,
+ min(sum[cur_sum].frac + prec_increment, DECIMAL_MAX_SCALE),
+ FALSE,&rounded_avg);
+ my_decimal2string(E_DEC_FATAL_ERROR, &rounded_avg, 0, 0, '0', s);
return s;
}
@@ -1036,13 +1047,19 @@ String *field_decimal::std(String *s, ha_rows rows)
s->set((double) 0.0, 1,my_thd_charset);
return s;
}
- my_decimal num, std_val, sum2, sum2d;
+ my_decimal num, tmp, sum2, sum2d;
+ double std_sqr;
+ int prec_increment= current_thd->variables.div_precincrement;
+
int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum);
- my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0);
- my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &std_val);
- my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0);
- my_decimal2string(E_DEC_FATAL_ERROR, &std_val, 0, 0, '0', s);
+ my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &tmp);
+ my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
+ my_decimal2double(E_DEC_FATAL_ERROR, &tmp, &std_sqr);
+ s->set(((double) std_sqr <= 0.0 ? 0.0 : sqrt(std_sqr)),
+ min(item->decimals + prec_increment, NOT_FIXED_DEC), my_thd_charset);
+
return s;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1de9411cad0..30dec528845 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -37,11 +37,11 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
TABLE_LIST *table_list, MEM_ROOT *mem_root);
static void free_cache_entry(TABLE *entry);
static void mysql_rm_tmp_tables(void);
-static my_bool open_new_frm(const char *path, const char *alias,
- const char *db, const char *table_name,
- uint db_stat, uint prgflag,
- uint ha_open_flags, TABLE *outparam,
- TABLE_LIST *table_desc, MEM_ROOT *mem_root);
+static bool open_new_frm(THD *thd, const char *path, const char *alias,
+ const char *db, const char *table_name,
+ uint db_stat, uint prgflag,
+ uint ha_open_flags, TABLE *outparam,
+ TABLE_LIST *table_desc, MEM_ROOT *mem_root);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
@@ -976,32 +976,57 @@ void wait_for_refresh(THD *thd)
}
-TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
+/*
+ Open table which is already name-locked by this thread.
+
+ SYNOPSIS
+ reopen_name_locked_table()
+ thd Thread handle
+ table_list TABLE_LIST object for table to be open, TABLE_LIST::table
+ member should point to TABLE object which was used for
+ name-locking.
+
+ NOTE
+ This function assumes that its caller already acquired LOCK_open mutex.
+
+ RETURN VALUE
+ FALSE - Success
+ TRUE - Error
+*/
+
+bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
{
- DBUG_ENTER("reopen_name_locked_table");
- if (thd->killed)
- DBUG_RETURN(0);
- TABLE *table;
+ TABLE *table= table_list->table;
TABLE_SHARE *share;
- if (!(table = table_list->table))
- DBUG_RETURN(0);
+ char *db= table_list->db;
+ char *table_name= table_list->table_name;
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ TABLE orig_table;
+ DBUG_ENTER("reopen_name_locked_table");
- char* db = thd->db ? thd->db : table_list->db;
- char* table_name = table_list->table_name;
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
+ safe_mutex_assert_owner(&LOCK_open);
+
+ if (thd->killed || !table)
+ DBUG_RETURN(TRUE);
+
+ orig_table= *table;
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
- pthread_mutex_lock(&LOCK_open);
if (open_unireg_entry(thd, table, db, table_name, table_name, 0,
thd->mem_root) ||
!(table->s->table_cache_key= memdup_root(&table->mem_root, (char*) key,
key_length)))
{
- delete table->triggers;
- closefrm(table);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
+ intern_close_table(table);
+ /*
+ If there was an error during opening of table (for example if it
+ does not exist) '*table' object can be wiped out. To be able
+ properly release name-lock in this case we should restore this
+ object to its original state.
+ */
+ *table= orig_table;
+ DBUG_RETURN(TRUE);
}
share= table->s;
@@ -1011,7 +1036,6 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
share->flush_version=0;
table->in_use = thd;
check_unused();
- pthread_mutex_unlock(&LOCK_open);
table->next = thd->open_tables;
thd->open_tables = table;
table->tablenr=thd->current_tablenr++;
@@ -1021,7 +1045,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= share->keys_in_use;
table->used_keys= share->keys_for_keyread;
- DBUG_RETURN(table);
+ DBUG_RETURN(FALSE);
}
@@ -1169,10 +1193,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
*/
{
char path[FN_REFLEN];
+ db_type not_used;
strxnmov(path, FN_REFLEN, mysql_data_home, "/", table_list->db, "/",
table_list->table_name, reg_ext, NullS);
(void) unpack_filename(path, path);
- if (mysql_frm_type(path) == FRMTYPE_VIEW)
+ if (mysql_frm_type(thd, path, &not_used) == FRMTYPE_VIEW)
{
TABLE tab;// will not be used (because it's VIEW) but have to be passed
table= &tab;
@@ -1731,7 +1756,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
thd->open_options, entry)) &&
(error != 5 ||
(fn_format(path, path, 0, reg_ext, MY_UNPACK_FILENAME),
- open_new_frm(path, alias, db, name,
+ open_new_frm(thd, path, alias, db, name,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
HA_GET_INDEX | HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
@@ -1947,11 +1972,11 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
derived/information schema tables and views possible. Thus "counter"
may be still zero for prelocked statement...
- NOTE: The above notes may be out of date. Please wait for psergey to
+ NOTE: The above notes may be out of date. Please wait for psergey to
document new prelocked behavior.
*/
-
- if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
+
+ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
thd->lex->sroutines_list.elements)
{
bool first_no_prelocking, need_prelocking;
@@ -2001,7 +2026,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
/* VIEW placeholder */
(*counter)--;
- /*
+ /*
tables->next_global list consists of two parts:
1) Query tables and underlying tables of views.
2) Tables used by all stored routines that this statement invokes on
@@ -2610,7 +2635,7 @@ bool rm_temporary_table(enum db_type base, char *path)
if (my_delete(path,MYF(0)))
error=1; /* purecov: inspected */
*fn_ext(path)='\0'; // remove extension
- handler *file=get_new_handler((TABLE*) 0, base);
+ handler *file= get_new_handler((TABLE*) 0, current_thd->mem_root, base);
if (file && file->delete_table(path))
{
error=1;
@@ -2658,6 +2683,47 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/*
+ Check column rights in given security context
+
+ SYNOPSIS
+ check_grant_column_in_sctx()
+ thd thread handler
+ grant grant information structure
+ db db name
+ table table name
+ name column name
+ length column name length
+ check_grants need to check grants
+ sctx 0 or security context
+
+ RETURN
+ FALSE OK
+ TRUE access denied
+*/
+
+static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
+ const char *db, const char *table,
+ const char *name, uint length,
+ bool check_grants,
+ Security_context *sctx)
+{
+ if (!check_grants)
+ return FALSE;
+ Security_context *save_security_ctx= thd->security_ctx;
+ bool res;
+ if (sctx)
+ {
+ thd->security_ctx= sctx;
+ }
+ res= check_grant_column(thd, grant, db, table, name, length);
+ thd->security_ctx= save_security_ctx;
+ return res;
+}
+#endif
+
+
/*
Find a field by name in a view that uses merge algorithm.
@@ -2708,11 +2774,11 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
*/
DBUG_RETURN(((Item_field*) (field_it.item()))->field);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grants &&
- check_grant_column(thd, &table_list->grant,
- table_list->view_db.str,
- table_list->view_name.str,
- name, length))
+ if (check_grant_column_in_sctx(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str, name, length,
+ check_grants,
+ table_list->security_ctx))
DBUG_RETURN(WRONG_GRANT);
#endif
// in PS use own arena or data will be freed after prepare
@@ -2789,7 +2855,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
Natural_join_column *nj_col;
Field *found_field;
Query_arena *arena, backup;
-
DBUG_ENTER("find_field_in_natural_join");
DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx",
name, (ulong) ref));
@@ -2814,6 +2879,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
if (nj_col->view_field)
{
+ Item *item;
/*
The found field is a view field, we do as in find_field_in_view()
and return a pointer to pointer to the Item of that field.
@@ -2821,7 +2887,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
if (register_tree_change)
arena= thd->activate_stmt_arena_if_needed(&backup);
- Item *item= nj_col->create_item(thd);
+ item= nj_col->create_item(thd);
if (register_tree_change && arena)
thd->restore_active_arena(arena, &backup);
@@ -2881,7 +2947,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
Field *
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr)
+ uint *cached_field_index_ptr,
+ Security_context *sctx)
{
Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr;
@@ -2890,7 +2957,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
if (cached_field_index < table->s->fields &&
- !my_strcasecmp(system_charset_info,
+ !my_strcasecmp(system_charset_info,
table->field[cached_field_index]->field_name, name))
field_ptr= table->field + cached_field_index;
else if (table->s->name_hash.records)
@@ -2921,9 +2988,10 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
update_field_dependencies(thd, field, table);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grants && check_grant_column(thd, &table->grant,
- table->s->db,
- table->s->table_name, name, length))
+ if (check_grant_column_in_sctx(thd, &table->grant,
+ table->s->db, table->s->table_name,
+ name, length,
+ check_grants, sctx))
field= WRONG_GRANT;
#endif
DBUG_RETURN(field);
@@ -3035,7 +3103,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
DBUG_ASSERT(table_list->table);
if ((fld= find_field_in_table(thd, table_list->table, name, length,
check_grants_table, allow_rowid,
- cached_field_index_ptr)))
+ cached_field_index_ptr,
+ table_list->security_ctx)))
*actual_table= table_list;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* check for views with temporary table algorithm */
@@ -3205,7 +3274,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
test(table_ref->table->
grant.want_privilege) &&
check_privileges,
- 1, &(item->cached_field_index));
+ 1, &(item->cached_field_index),
+ table_ref->security_ctx);
else
found= find_field_in_table_ref(thd, table_ref, name, item->name,
NULL, NULL, length, ref,
@@ -4293,7 +4363,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->set_query_id=set_query_id;
thd->allow_sum_func= allow_sum_func;
- thd->where="field list";
+ thd->where= THD::DEFAULT_WHERE;
/*
To prevent fail on forward lookup we fill it with zerows,
@@ -4345,8 +4415,12 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
{
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE)
- list= make_leaves_list(list, table->ancestor);
+ if (table->merge_underlying_list)
+ {
+ DBUG_ASSERT(table->view &&
+ table->effective_algorithm == VIEW_ALGORITHM_MERGE);
+ list= make_leaves_list(list, table->merge_underlying_list);
+ }
else
{
*list= table;
@@ -4446,16 +4520,17 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
table_list;
table_list= table_list->next_local)
{
- if (table_list->ancestor)
+ if (table_list->merge_underlying_list)
{
- DBUG_ASSERT(table_list->view);
+ DBUG_ASSERT(table_list->view &&
+ table_list->effective_algorithm == VIEW_ALGORITHM_MERGE);
Query_arena *arena= thd->stmt_arena, backup;
bool res;
if (arena->is_conventional())
arena= 0; // For easier test
else
thd->set_n_backup_active_arena(arena, &backup);
- res= table_list->setup_ancestor(thd);
+ res= table_list->setup_underlying(thd);
if (arena)
thd->restore_active_arena(arena, &backup);
if (res)
@@ -5233,6 +5308,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
SYNOPSIS
open_new_frm()
+ THD thread handler
path path to .frm
alias alias for table
db database
@@ -5246,8 +5322,8 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
mem_root temporary MEM_ROOT for parsing
*/
-static my_bool
-open_new_frm(const char *path, const char *alias,
+static bool
+open_new_frm(THD *thd, const char *path, const char *alias,
const char *db, const char *table_name,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
@@ -5269,7 +5345,7 @@ open_new_frm(const char *path, const char *alias,
my_error(ER_WRONG_OBJECT, MYF(0), db, table_name, "BASE TABLE");
goto err;
}
- if (mysql_make_view(parser, table_desc))
+ if (mysql_make_view(thd, parser, table_desc))
goto err;
}
else
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index f17825e6d2c..c150489f311 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1204,6 +1204,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
#endif /*!EMBEDDED_LIBRARY*/
thd->limit_found_rows = query->found_rows();
+ thd->status_var.last_query_cost= 0.0;
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(1); // Result sent to client
@@ -2207,15 +2208,10 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
tables_used->view_db.length + 1,
HA_CACHE_TBL_NONTRANSACT, 0, 0))
DBUG_RETURN(0);
- {
- TABLE_COUNTER_TYPE inc= register_tables_from_list(tables_used->ancestor,
- n + 1,
- block_table + 1);
- if (!inc)
- DBUG_RETURN(0);
- n+= inc;
- block_table+= inc;
- }
+ /*
+ We do not need to register view tables here because they are already
+ present in the global list.
+ */
}
else
{
@@ -2831,13 +2827,6 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
tables_used->view_name.str,
tables_used->view_db.str));
*tables_type|= HA_CACHE_TBL_NONTRANSACT;
- {
- TABLE_COUNTER_TYPE subcount;
- if (!(subcount= process_and_count_tables(tables_used->ancestor,
- tables_type)))
- DBUG_RETURN(0);
- table_count+= subcount;
- }
}
else
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fc7ea6a2794..fc9df020b6c 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -44,6 +44,8 @@
*/
char internal_table_name[2]= "*";
+const char * const THD::DEFAULT_WHERE= "field list";
+
/*****************************************************************************
** Instansiate templates
@@ -218,6 +220,7 @@ THD::THD()
#ifndef EMBEDDED_LIBRARY
net.vio=0;
#endif
+ client_capabilities= 0; // minimalistic client
net.last_error[0]=0; // If error on boot
net.query_cache_query=0; // If error on boot
ull=0;
@@ -233,7 +236,7 @@ THD::THD()
/* Variables with default values */
proc_info="login";
- where="field list";
+ where= THD::DEFAULT_WHERE;
server_id = ::server_id;
slave_net = 0;
command=COM_CONNECT;
@@ -544,6 +547,8 @@ void THD::cleanup_after_query()
}
/* Free Items that were created during this execution */
free_items();
+ /* Reset where. */
+ where= THD::DEFAULT_WHERE;
}
/*
@@ -1703,15 +1708,19 @@ Statement_map::Statement_map() :
int Statement_map::insert(Statement *statement)
{
- int rc= my_hash_insert(&st_hash, (byte *) statement);
+ int res= my_hash_insert(&st_hash, (byte *) statement);
+ if (res)
+ return res;
if (statement->name.str)
{
- if ((rc= my_hash_insert(&names_hash, (byte*)statement)))
+ if ((res= my_hash_insert(&names_hash, (byte*)statement)))
+ {
hash_delete(&st_hash, (byte*)statement);
+ return res;
+ }
}
- if (rc == 0)
- last_found_statement= statement;
- return rc;
+ last_found_statement= statement;
+ return res;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 9e751c37608..0a34de11528 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -189,8 +189,11 @@ class MYSQL_LOG: public TC_LOG
{
private:
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
- pthread_mutex_t LOCK_log, LOCK_index;
+ pthread_mutex_t LOCK_log, LOCK_index, LOCK_readers;
+ pthread_mutex_t LOCK_prep_xids;
+ pthread_cond_t COND_prep_xids;
pthread_cond_t update_cond;
+ pthread_cond_t reset_cond;
ulonglong bytes_written;
time_t last_time,query_start;
IO_CACHE log_file;
@@ -198,21 +201,6 @@ class MYSQL_LOG: public TC_LOG
char *name;
char time_buff[20],db[NAME_LEN+1];
char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN];
- // current file sequence number for load data infile binary logging
- uint file_id;
- uint open_count; // For replication
- volatile enum_log_type log_type;
- enum cache_type io_cache_type;
- bool write_error, inited;
- bool need_start_event;
- /*
- no_auto_events means we don't want any of these automatic events :
- Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't want
- a Rotate_log event to be written to the relay log. When we start a relay log
- etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
- In 5.0 it's 0 for relay logs too!
- */
- bool no_auto_events;
/*
The max size before rotation (usable only if log_type == LOG_BIN: binary
logs and relay logs).
@@ -224,13 +212,38 @@ class MYSQL_LOG: public TC_LOG
fix_max_relay_log_size).
*/
ulong max_size;
-
ulong prepared_xids; /* for tc log - number of xids to remember */
- pthread_mutex_t LOCK_prep_xids;
- pthread_cond_t COND_prep_xids;
+ volatile enum_log_type log_type;
+ enum cache_type io_cache_type;
+ // current file sequence number for load data infile binary logging
+ uint file_id;
+ uint open_count; // For replication
+ int readers_count;
+ bool reset_pending;
+ bool write_error, inited;
+ bool need_start_event;
+ /*
+ no_auto_events means we don't want any of these automatic events :
+ Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't
+ want a Rotate_log event to be written to the relay log. When we start a
+ relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
+ In 5.0 it's 0 for relay logs too!
+ */
+ bool no_auto_events;
friend class Log_event;
public:
+ /*
+ These describe the log's format. This is used only for relay logs.
+ _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
+ necessary to have 2 distinct objects, because the I/O thread may be reading
+ events in a different format from what the SQL thread is reading (consider
+ the case of a master which has been upgraded from 5.0 to 5.1 without doing
+ RESET MASTER, or from 4.x to 5.0).
+ */
+ Format_description_log_event *description_event_for_exec,
+ *description_event_for_queue;
+
MYSQL_LOG();
/*
note that there's no destructor ~MYSQL_LOG() !
@@ -243,18 +256,6 @@ public:
int log(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid);
int recover(IO_CACHE *log, Format_description_log_event *fdle);
-
- /*
- These describe the log's format. This is used only for relay logs.
- _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
- necessary to have 2 distinct objects, because the I/O thread may be reading
- events in a different format from what the SQL thread is reading (consider
- the case of a master which has been upgraded from 5.0 to 5.1 without doing
- RESET MASTER, or from 4.x to 5.0).
- */
- Format_description_log_event *description_event_for_exec,
- *description_event_for_queue;
-
void reset_bytes_written()
{
bytes_written = 0;
@@ -334,6 +335,9 @@ public:
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);
+ inline bool is_reset_pending() { return reset_pending; }
+ void readers_addref();
+ void readers_release();
void close(uint exiting);
// iterating through the log index file
@@ -1115,6 +1119,14 @@ class THD :public Statement,
public Open_tables_state
{
public:
+ /*
+ Constant for THD::where initialization in the beginning of every query.
+
+ It's needed because we do not save/restore THD::where normally during
+ primary (non subselect) query execution.
+ */
+ static const char * const DEFAULT_WHERE;
+
#ifdef EMBEDDED_LIBRARY
struct st_mysql *mysql;
struct st_mysql_data *data;
@@ -1911,6 +1923,7 @@ typedef struct st_sort_field {
Field *field; /* Field to sort */
Item *item; /* Item if not sorting fields */
uint length; /* Length of sort field */
+ uint suffix_length; /* Length suffix (0-4) */
Item_result result_type; /* Type of item */
bool reverse; /* if descending sort */
bool need_strxnfrm; /* If we have to use strxnfrm() */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 584601fe202..816aba25218 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool using_limit=limit != HA_POS_ERROR;
bool transactional_table, safe_update, const_cond;
ha_rows deleted;
+ uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_delete");
@@ -141,27 +142,42 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
tables.table = table;
tables.alias = table_list->alias;
- table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
- MYF(MY_FAE | MY_ZEROFILL));
if (select_lex->setup_ref_array(thd, order->elements) ||
setup_order(thd, select_lex->ref_pointer_array, &tables,
- fields, all_fields, (ORDER*) order->first) ||
- !(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) ||
+ fields, all_fields, (ORDER*) order->first))
+ {
+ delete select;
+ free_underlaid_joins(thd, &thd->lex->select_lex);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!select && limit != HA_POS_ERROR)
+ usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);
+
+ if (usable_index == MAX_KEY)
+ {
+ table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
+
+ if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
+ &length)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
- select, HA_POS_ERROR,
- &examined_rows))
+ select, HA_POS_ERROR,
+ &examined_rows))
== HA_POS_ERROR)
- {
+ {
+ delete select;
+ free_underlaid_joins(thd, &thd->lex->select_lex);
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Filesort has already found and selected the rows we want to delete,
+ so we don't need the where clause
+ */
delete select;
free_underlaid_joins(thd, select_lex);
- DBUG_RETURN(TRUE);
+ select= 0;
}
- /*
- Filesort has already found and selected the rows we want to delete,
- so we don't need the where clause
- */
- delete select;
- select= 0;
}
/* If quick select is used, initialize it before retrieving rows. */
@@ -171,7 +187,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(TRUE);
}
- init_read_record(&info,thd,table,select,1,1);
+ if (usable_index==MAX_KEY)
+ init_read_record(&info,thd,table,select,1,1);
+ else
+ init_read_record_idx(&info, thd, table, 1, usable_index);
+
deleted=0L;
init_ftfuncs(thd, select_lex, 1);
thd->proc_info="updating";
@@ -404,8 +424,9 @@ bool mysql_multi_delete_prepare(THD *thd)
if (!(target_tbl->table= target_tbl->correspondent_table->table))
{
DBUG_ASSERT(target_tbl->correspondent_table->view &&
- target_tbl->correspondent_table->ancestor &&
- target_tbl->correspondent_table->ancestor->next_local);
+ target_tbl->correspondent_table->merge_underlying_list &&
+ target_tbl->correspondent_table->merge_underlying_list->
+ next_local);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
target_tbl->correspondent_table->view_db.str,
target_tbl->correspondent_table->view_name.str);
@@ -830,7 +851,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
if (!dont_send_ok)
{
db_type table_type;
- if ((table_type=get_table_type(thd, path)) == DB_TYPE_UNKNOWN)
+ mysql_frm_type(thd, path, &table_type);
+ if (table_type == DB_TYPE_UNKNOWN)
{
my_error(ER_NO_SUCH_TABLE, MYF(0),
table_list->db, table_list->table_name);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 74b239e1637..e1817985cbd 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -35,14 +35,14 @@
processor procedure of derived table processing
RETURN
- 0 ok
- 1 Error and error message given
+ FALSE OK
+ TRUE Error
*/
-int
-mysql_handle_derived(LEX *lex, int (*processor)(THD*, LEX*, TABLE_LIST*))
+bool
+mysql_handle_derived(LEX *lex, bool (*processor)(THD*, LEX*, TABLE_LIST*))
{
- int res= 0;
+ bool res= FALSE;
if (lex->derived_tables)
{
lex->thd->derived_tables_processing= TRUE;
@@ -95,16 +95,16 @@ out:
close_thread_tables()
RETURN
- 0 ok
- 1 Error and an error message was given
+ FALSE OK
+ TRUE Error
*/
-int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
+bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{
SELECT_LEX_UNIT *unit= orig_table_list->derived;
- int res= 0;
ulonglong create_options;
DBUG_ENTER("mysql_derived_prepare");
+ bool res= FALSE;
if (unit)
{
SELECT_LEX *first_select= unit->first_select();
@@ -118,7 +118,7 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
sl->context.outer_context= 0;
if (!(derived_result= new select_union))
- DBUG_RETURN(1); // out of memory
+ DBUG_RETURN(TRUE); // out of memory
// st_select_lex_unit::prepare correctly work for single select
if ((res= unit->prepare(thd, derived_result, 0)))
@@ -184,7 +184,10 @@ exit:
table->derived_select_number= first_select->select_number;
table->s->tmp_table= TMP_TABLE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table->grant.privilege= SELECT_ACL;
+ if (orig_table_list->referencing_view)
+ table->grant= orig_table_list->grant;
+ else
+ table->grant.privilege= SELECT_ACL;
#endif
orig_table_list->db= (char *)"";
orig_table_list->db_length= 0;
@@ -195,8 +198,8 @@ exit:
thd->derived_tables= table;
}
}
- else if (orig_table_list->ancestor)
- orig_table_list->set_ancestor();
+ else if (orig_table_list->merge_underlying_list)
+ orig_table_list->set_underlying_merge();
DBUG_RETURN(res);
}
@@ -220,15 +223,15 @@ exit:
Due to evaluation of LIMIT clause it can not be used at prepared stage.
RETURN
- 0 ok
- 1 Error and an error message was given
+ FALSE OK
+ TRUE Error
*/
-int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
+bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{
TABLE *table= orig_table_list->table;
SELECT_LEX_UNIT *unit= orig_table_list->derived;
- int res= 0;
+ bool res= FALSE;
/*check that table creation pass without problem and it is derived table */
if (table && unit)
@@ -271,7 +274,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
there were no derived tables
*/
if (derived_result->flush())
- res= 1;
+ res= TRUE;
if (!lex->describe)
unit->cleanup();
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 2e262569386..191a6e0a1fd 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -144,6 +144,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
thd->really_abort_on_warning()) ?
MYSQL_ERROR::WARN_LEVEL_ERROR : level))
{
+ if (! thd->spcont->found_handler_here())
+ thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_RETURN(NULL);
}
query_cache_abort(&thd->net);
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index dc2255fd6e8..0715aeeaa5b 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -599,7 +599,8 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen,
{
Item *cond= new Item_func_like(new Item_field(pfname),
new Item_string(mask,mlen,pfname->charset()),
- new Item_string("\\",1,&my_charset_latin1));
+ new Item_string("\\",1,&my_charset_latin1),
+ FALSE);
if (thd->is_fatal_error)
return 0; // OOM
return prepare_simple_select(thd, cond, table, error);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index beca9842e6d..8877cc17bf0 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1822,7 +1822,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
#endif
if (thd->killed || di->status)
break;
- if (error == ETIMEDOUT)
+ if (error == ETIMEDOUT || error == ETIME)
{
thd->killed= THD::KILL_CONNECTION;
break;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d76e8d04ae6..64f9256cc83 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -176,6 +176,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->spcont= NULL;
lex->proc_list.first= 0;
lex->query_tables_own_last= 0;
+ lex->escape_used= FALSE;
if (lex->sroutines.records)
my_hash_reset(&lex->sroutines);
@@ -1134,6 +1135,7 @@ void st_select_lex::init_query()
ref_pointer_array= 0;
select_n_having_items= 0;
subquery_in_having= explicit_limit= 0;
+ is_item_list_lookup= 0;
first_execution= 1;
first_cond_optimization= 1;
parsing_place= NO_MATTER;
@@ -1166,6 +1168,7 @@ void st_select_lex::init_select()
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
+
}
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7640b6eb569..96ed32a0d2e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -362,8 +362,8 @@ public:
friend class st_select_lex_unit;
friend bool mysql_new_select(struct st_lex *lex, bool move_down);
- friend my_bool mysql_make_view (File_parser *parser,
- TABLE_LIST *table);
+ friend bool mysql_make_view(THD *thd, File_parser *parser,
+ TABLE_LIST *table);
private:
void fast_exclude();
};
@@ -387,12 +387,12 @@ protected:
select_result *result;
ulong found_rows_for_union;
bool res;
+public:
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
executed, // already executed
cleaned;
-public:
// list of fields which points to temporary table for union
List<Item> item_list;
/*
@@ -483,6 +483,7 @@ public:
List<Item> item_list; /* list of fields & expressions */
List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
+ bool is_item_list_lookup;
/*
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
select_lex for calling mysql_select under results of union
@@ -639,6 +640,11 @@ public:
SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs).
*/
bool cleanup();
+ /*
+ Recursively cleanup the join of this select lex and of all nested
+ select lexes.
+ */
+ void cleanup_all_joins(bool full);
};
typedef class st_select_lex SELECT_LEX;
@@ -746,6 +752,7 @@ typedef struct st_lex
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
st_lex_user *create_view_definer;
+ char *create_view_start;
char *create_view_select_start;
/* Partition info structure filled in by PARTITION BY parse part */
partition_info *part_info;
@@ -810,6 +817,11 @@ typedef struct st_lex
*/
uint table_count;
uint8 describe;
+ /*
+ A flag that indicates what kinds of derived tables are present in the
+ query (0 if no derived tables, otherwise a combination of flags
+ DERIVED_SUBQUERY and DERIVED_VIEW).
+ */
uint8 derived_tables;
uint8 create_view_algorithm;
uint8 create_view_check;
@@ -904,6 +916,8 @@ typedef struct st_lex
during replication ("LOCAL 'filename' REPLACE INTO" part).
*/
uchar *fname_start, *fname_end;
+
+ bool escape_used;
st_lex();
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 895065241f4..44ddf11757a 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1025,8 +1025,20 @@ int READ_INFO::read_field()
*to++= (byte) escape_char;
goto found_eof;
}
- *to++ = (byte) unescape((char) chr);
- continue;
+ /*
+ When escape_char == enclosed_char, we treat it like we do for
+ handling quotes in SQL parsing -- you can double-up the
+ escape_char to include it literally, but it doesn't do escapes
+ like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
+ with data like: "fie""ld1", "field2"
+ */
+ if (escape_char != enclosed_char || chr == escape_char)
+ {
+ *to++ = (byte) unescape((char) chr);
+ continue;
+ }
+ PUSH(chr);
+ chr= escape_char;
}
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
if (chr == line_term_char)
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 34334d3a01d..1d3acd1696c 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -58,12 +58,14 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
set_timespec(abstime, flush_time);
reset_flush_time = FALSE;
}
- while (!manager_status && !error && !abort_loop)
- error = pthread_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
+ while (!manager_status && (!error || error == EINTR) && !abort_loop)
+ error= pthread_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
}
else
- while (!manager_status && !error && !abort_loop)
- error = pthread_cond_wait(&COND_manager, &LOCK_manager);
+ {
+ while (!manager_status && (!error || error == EINTR) && !abort_loop)
+ error= pthread_cond_wait(&COND_manager, &LOCK_manager);
+ }
status = manager_status;
manager_status = 0;
pthread_mutex_unlock(&LOCK_manager);
@@ -71,7 +73,7 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
if (abort_loop)
break;
- if (error) /* == ETIMEDOUT */
+ if (error == ETIMEDOUT || error == ETIME)
{
flush_tables();
error = 0;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f5391cd546d..939961ab7e8 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1769,6 +1769,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* Saved variable value */
my_bool old_innodb_table_locks=
IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
+ /* used as fields initializator */
+ lex_start(thd, 0, 0);
statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
@@ -2319,8 +2321,6 @@ mysql_execute_command(THD *thd)
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
SELECT_LEX *select_lex= &lex->select_lex;
- bool slave_fake_lock= 0;
- MYSQL_LOCK *fake_prev_lock= 0;
/* first table of first SELECT_LEX */
TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
/* list of all tables in query */
@@ -2369,34 +2369,21 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
if (thd->slave_thread)
{
- if (lex->sql_command == SQLCOM_UPDATE_MULTI)
- {
- DBUG_PRINT("info",("need faked locked tables"));
-
- if (check_multi_update_lock(thd))
- goto error;
-
- /* Fix for replication, the tables are opened and locked,
- now we pretend that we have performed a LOCK TABLES action */
-
- fake_prev_lock= thd->locked_tables;
- if (thd->lock)
- thd->locked_tables= thd->lock;
- thd->lock= 0;
- slave_fake_lock= 1;
- }
/*
- Skip if we are in the slave thread, some table rules have been
- given and the table list says the query should not be replicated.
+ Check if statment should be skipped because of slave filtering
+ rules
Exceptions are:
+ - UPDATE MULTI: For this statement, we want to check the filtering
+ rules later in the code
- SET: we always execute it (Not that many SET commands exists in
the binary log anyway -- only 4.1 masters write SET statements,
in 5.0 there are no SET statements in the binary log)
- DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
have stale files on slave caused by exclusion of one tmp table).
*/
- if (!(lex->sql_command == SQLCOM_SET_OPTION) &&
+ if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
+ !(lex->sql_command == SQLCOM_SET_OPTION) &&
!(lex->sql_command == SQLCOM_DROP_TABLE &&
lex->drop_temporary && lex->drop_if_exists) &&
all_tables_not_ok(thd, all_tables))
@@ -2419,7 +2406,7 @@ mysql_execute_command(THD *thd)
}
#endif
}
-#endif /* !HAVE_REPLICATION */
+#endif /* HAVE_REPLICATION */
/*
When option readonly is set deny operations which change tables.
@@ -3211,23 +3198,36 @@ end_with_restore_list:
if (result != 2)
break;
case SQLCOM_UPDATE_MULTI:
+ {
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ /* if we switched from normal update, rights are checked */
+ if (result != 2)
{
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- /* if we switched from normal update, rights are checked */
- if (result != 2)
- {
- if ((res= multi_update_precheck(thd, all_tables)))
- break;
- }
- else
- res= 0;
-
- res= mysql_multi_update(thd, all_tables,
- &select_lex->item_list,
- &lex->value_list,
- select_lex->where,
- select_lex->options,
- lex->duplicates, lex->ignore, unit, select_lex);
+ if ((res= multi_update_precheck(thd, all_tables)))
+ break;
+ }
+ else
+ res= 0;
+
+ if ((res= mysql_multi_update_prepare(thd)))
+ break;
+
+#ifdef HAVE_REPLICATION
+ /* Check slave filtering rules */
+ if (thd->slave_thread && all_tables_not_ok(thd, all_tables))
+ {
+ /* we warn the slave SQL thread */
+ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ break;
+ }
+#endif /* HAVE_REPLICATION */
+
+ res= mysql_multi_update(thd, all_tables,
+ &select_lex->item_list,
+ &lex->value_list,
+ select_lex->where,
+ select_lex->options,
+ lex->duplicates, lex->ignore, unit, select_lex);
break;
}
case SQLCOM_REPLACE:
@@ -3688,6 +3688,8 @@ end_with_restore_list:
if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+ if (end_active_trans(thd))
+ goto error;
if (!(res= mysql_create_user(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
@@ -3704,6 +3706,8 @@ end_with_restore_list:
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+ if (end_active_trans(thd))
+ goto error;
if (!(res= mysql_drop_user(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
@@ -3720,6 +3724,8 @@ end_with_restore_list:
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+ if (end_active_trans(thd))
+ goto error;
if (!(res= mysql_rename_user(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
@@ -4066,6 +4072,19 @@ end_with_restore_list:
DBUG_ASSERT(lex->sphead != 0);
+ if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
+ {
+ if (! thd->db)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+ lex->sphead->m_db.length= strlen(thd->db);
+ lex->sphead->m_db.str= thd->db;
+ }
+
if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
is_schema_db(lex->sphead->m_db.str)))
{
@@ -4075,13 +4094,10 @@ end_with_restore_list:
}
if (end_active_trans(thd))
- goto error;
-
- if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
{
- lex->sphead->m_db.length= strlen(thd->db);
- lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db,
- lex->sphead->m_db.length);
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
}
name= lex->sphead->name(&namelen);
@@ -4108,11 +4124,23 @@ end_with_restore_list:
goto error;
}
+ /*
+ We need to copy name and db in order to use them for
+ check_routine_access which is called after lex->sphead has
+ been deleted.
+ */
name= thd->strdup(name);
- db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
+ lex->sphead->m_db.str= db= thd->strmake(lex->sphead->m_db.str,
+ lex->sphead->m_db.length);
res= (result= lex->sphead->create(thd));
if (result == SP_OK)
{
+ /*
+ We must cleanup the unit and the lex here because
+ sp_grant_privileges calls (indirectly) db_find_routine,
+ which in turn may call yyparse with THD::lex.
+ TODO: fix db_find_routine to use a temporary lex.
+ */
lex->unit.cleanup();
delete lex->sphead;
lex->sphead= 0;
@@ -4514,6 +4542,9 @@ end_with_restore_list:
}
case SQLCOM_CREATE_VIEW:
{
+ if (end_active_trans(thd))
+ goto error;
+
if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) &&
mysql_bin_log.is_open())
{
@@ -4528,7 +4559,8 @@ end_with_restore_list:
command[thd->lex->create_view_mode].length);
view_store_options(thd, first_table, &buff);
buff.append("VIEW ", 5);
- if (!first_table->current_db_used)
+ /* Test if user supplied a db (ie: we did not use thd->db) */
+ if (first_table->db != thd->db && first_table->db[0])
{
append_identifier(thd, &buff, first_table->db,
first_table->db_length);
@@ -4560,6 +4592,9 @@ end_with_restore_list:
}
case SQLCOM_CREATE_TRIGGER:
{
+ if (end_active_trans(thd))
+ goto error;
+
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
/* We don't care about trigger body after this point */
@@ -4569,6 +4604,9 @@ end_with_restore_list:
}
case SQLCOM_DROP_TRIGGER:
{
+ if (end_active_trans(thd))
+ goto error;
+
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
}
@@ -4776,14 +4814,6 @@ error:
res= 1;
cleanup:
- if (unlikely(slave_fake_lock))
- {
- DBUG_PRINT("info",("undoing faked lock"));
- thd->lock= thd->locked_tables;
- thd->locked_tables= fake_prev_lock;
- if (thd->lock == thd->locked_tables)
- thd->lock= 0;
- }
DBUG_RETURN(res || thd->net.report_error);
}
@@ -4854,7 +4884,6 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool db_is_pattern= test(want_access & GRANT_ACL);
#endif
ulong dummy;
- const char *db_name;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
db ? db : "", want_access, sctx->master_access));
@@ -4872,15 +4901,16 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_RETURN(TRUE); /* purecov: tested */
}
- db_name= db ? db : thd->db;
if (schema_db)
{
if (want_access & ~(SELECT_ACL | EXTRA_ACL))
{
if (!no_errors)
+ {
+ const char *db_name= db ? db : thd->db;
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user,
- sctx->priv_host, db_name);
+ sctx->priv_user, sctx->priv_host, db_name);
+ }
DBUG_RETURN(TRUE);
}
else
@@ -5000,8 +5030,14 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
uint found=0;
ulong found_access=0;
- TABLE_LIST *org_tables=tables;
- for (; tables; tables= tables->next_global)
+ TABLE_LIST *org_tables= tables;
+ TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
+ /*
+ The check that first_not_own_table is not reached is for the case when
+ the given table list refers to the list for prelocking (contains tables
+ of other queries). For simple queries first_not_own_table is 0.
+ */
+ for (; tables != first_not_own_table; tables= tables->next_global)
{
if (tables->schema_table &&
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
@@ -5012,6 +5048,11 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
information_schema_name.str);
return TRUE;
}
+ /*
+ Register access for view underlying table.
+ Remove SHOW_VIEW_ACL, because it will be checked during making view
+ */
+ tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
if (tables->derived || tables->schema_table || tables->belong_to_view ||
(tables->table && (int)tables->table->s->tmp_table) ||
my_tz_check_n_skip_implicit_tables(&tables,
@@ -5055,11 +5096,16 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name,
tables->db= db;
tables->table_name= tables->alias= name;
- if ((thd->security_ctx->master_access & want_access) == want_access &&
- !thd->db)
+ /*
+ The following test is just a shortcut for check_access() (to avoid
+ calculating db_access) under the assumption that it's common to
+ give persons global right to execute all stored SP (but not
+ necessary to create them).
+ */
+ if ((thd->security_ctx->master_access & want_access) == want_access)
tables->grant.privilege= want_access;
else if (check_access(thd,want_access,db,&tables->grant.privilege,
- 0, no_errors, test(tables->schema_table)))
+ 0, no_errors, 0))
return TRUE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -5760,7 +5806,7 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
case FIELD_TYPE_NULL:
break;
case FIELD_TYPE_NEWDECIMAL:
- if (!length)
+ if (!length && !new_field->decimals)
new_field->length= 10;
if (new_field->length > DECIMAL_MAX_PRECISION)
{
@@ -6146,14 +6192,12 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
ptr->db= thd->db;
ptr->db_length= thd->db_length;
- ptr->current_db_used= 1;
}
else
{
/* The following can't be "" as we may do 'casedn_str()' on it */
ptr->db= empty_c_string;
ptr->db_length= 0;
- ptr->current_db_used= 1;
}
if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
ptr->db= thd->strdup(ptr->db);
@@ -6168,8 +6212,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
- if (!my_strcasecmp(system_charset_info, ptr->db,
- information_schema_name.str))
+ if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
+ information_schema_name.str))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
if (!schema_table ||
@@ -6916,57 +6960,6 @@ bool check_simple_select()
return 0;
}
-/*
- Setup locking for multi-table updates. Used by the replication slave.
- Replication slave SQL thread examines (all_tables_not_ok()) the
- locking state of referenced tables to determine if the query has to
- be executed or ignored. Since in multi-table update, the
- 'default' lock is read-only, this lock is corrected early enough by
- calling this function, before the slave decides to execute/ignore.
-
- SYNOPSIS
- check_multi_update_lock()
- thd Current thread
-
- RETURN VALUES
- 0 ok
- 1 error
-*/
-static bool check_multi_update_lock(THD *thd)
-{
- bool res= 1;
- LEX *lex= thd->lex;
- TABLE_LIST *table, *tables= lex->query_tables;
- DBUG_ENTER("check_multi_update_lock");
-
- if (check_db_used(thd, tables))
- goto error;
-
- /*
- Ensure that we have UPDATE or SELECT privilege for each table
- The exact privilege is checked in mysql_multi_update()
- */
- for (table= tables ; table ; table= table->next_local)
- {
- TABLE_LIST *save= table->next_local;
- table->next_local= 0;
- if ((check_access(thd, UPDATE_ACL, table->db,
- &table->grant.privilege,0,1, test(table->schema_table)) ||
- (grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) &&
- check_one_table_access(thd, SELECT_ACL, table))
- goto error;
- table->next_local= save;
- }
-
- if (mysql_multi_update_prepare(thd))
- goto error;
-
- res= 0;
-
-error:
- DBUG_RETURN(res);
-}
-
Comp_creator *comp_eq_creator(bool invert)
{
@@ -7453,9 +7446,9 @@ Item *negate_expression(THD *thd, Item *expr)
Assign as view definer current user
SYNOPSIS
- default_definer()
- Secytity_context current decurity context
- definer structure where it should be assigned
+ default_view_definer()
+ sctx current security context
+ definer structure where it should be assigned
RETURN
FALSE OK
@@ -7466,15 +7459,14 @@ bool default_view_definer(Security_context *sctx, st_lex_user *definer)
{
definer->user.str= sctx->priv_user;
definer->user.length= strlen(sctx->priv_user);
- if (*sctx->priv_host != 0)
- {
- definer->host.str= sctx->priv_host;
- definer->host.length= strlen(sctx->priv_host);
- }
- else
+
+ if (!*sctx->priv_host)
{
my_error(ER_NO_VIEW_USER, MYF(0));
return TRUE;
}
+
+ definer->host.str= sctx->priv_host;
+ definer->host.length= strlen(sctx->priv_host);
return FALSE;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 16433e42e3c..6e6961080cd 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -101,6 +101,11 @@ public:
class Prepared_statement: public Statement
{
public:
+ enum flag_values
+ {
+ IS_IN_USE= 1
+ };
+
THD *thd;
Select_fetch_protocol_prep result;
Protocol *protocol;
@@ -131,19 +136,8 @@ public:
bool execute(String *expanded_query, bool open_cursor);
/* Destroy this statement */
bool deallocate();
-
- /* Possible values of flags */
-#if defined(_MSC_VER) && _MSC_VER < 1300
- static const int IS_IN_USE;
-#else
- static const int IS_IN_USE= 1;
-#endif
};
-/* VC6 can't handle initializing in declaration */
-#if defined(_MSC_VER) && _MSC_VER < 1300
-const int Prepared_statement::IS_IN_USE= 1;
-#endif
/******************************************************************************
Implementation
@@ -1164,6 +1158,7 @@ static int mysql_test_update(Prepared_statement *stmt,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= want_privilege;
table_list->table->grant.want_privilege= want_privilege;
+ table_list->register_want_access(want_privilege);
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
@@ -1175,6 +1170,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->grant.want_privilege=
table_list->table->grant.want_privilege=
(SELECT_ACL & ~table_list->table->grant.privilege);
+ table_list->register_want_access(SELECT_ACL);
#endif
if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
goto error;
@@ -1748,6 +1744,8 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_ROLLBACK:
case SQLCOM_TRUNCATE:
case SQLCOM_CALL:
+ case SQLCOM_CREATE_VIEW:
+ case SQLCOM_DROP_VIEW:
break;
default:
@@ -1830,7 +1828,7 @@ static bool init_param_array(Prepared_statement *stmt)
void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
{
Prepared_statement *stmt= new Prepared_statement(thd, &thd->protocol_prep);
- bool rc;
+ bool error;
DBUG_ENTER("mysql_stmt_prepare");
DBUG_PRINT("prep_query", ("%s", packet));
@@ -1853,12 +1851,12 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
- rc= stmt->prepare(packet, packet_length);
+ error= stmt->prepare(packet, packet_length);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
- if (rc)
+ if (error)
{
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
@@ -1900,7 +1898,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
CHARSET_INFO *to_cs= thd->variables.collation_connection;
bool needs_conversion;
user_var_entry *entry;
- String *pstr= &str;
+ String *var_value= &str;
uint32 unused, len;
/*
Convert @var contents to string in connection character set. Although
@@ -1914,13 +1912,13 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
&& entry->value)
{
my_bool is_var_null;
- pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
+ var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
/*
NULL value of variable checked early as entry->value so here
we can't get NULL in normal conditions
*/
DBUG_ASSERT(!is_var_null);
- if (!pstr)
+ if (!var_value)
goto end;
}
else
@@ -1932,22 +1930,25 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
str.set("NULL", 4, &my_charset_latin1);
}
- needs_conversion= String::needs_conversion(pstr->length(),
- pstr->charset(), to_cs, &unused);
+ needs_conversion= String::needs_conversion(var_value->length(),
+ var_value->charset(), to_cs,
+ &unused);
- len= needs_conversion ? pstr->length() * to_cs->mbmaxlen : pstr->length();
+ len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
+ var_value->length());
if (!(query_str= alloc_root(thd->mem_root, len+1)))
goto end;
if (needs_conversion)
{
uint dummy_errors;
- len= copy_and_convert(query_str, len, to_cs, pstr->ptr(), pstr->length(),
- pstr->charset(), &dummy_errors);
+ len= copy_and_convert(query_str, len, to_cs, var_value->ptr(),
+ var_value->length(), var_value->charset(),
+ &dummy_errors);
}
else
- memcpy(query_str, pstr->ptr(), pstr->length());
- query_str[len]= '\0';
+ memcpy(query_str, var_value->ptr(), var_value->length());
+ query_str[len]= '\0'; // Safety (mostly for debug)
*query_len= len;
}
else
@@ -1997,10 +1998,9 @@ void mysql_sql_stmt_prepare(THD *thd)
Prepared_statement *stmt;
const char *query;
uint query_len;
-
DBUG_ENTER("mysql_sql_stmt_prepare");
-
DBUG_ASSERT(thd->protocol == &thd->protocol_simple);
+
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
/*
@@ -2172,8 +2172,9 @@ static void reset_stmt_params(Prepared_statement *stmt)
client, otherwise an error message is set in THD.
*/
-void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
+void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
+ uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) ((uchar) packet[4]);
/* Query text for binary, general or slow log, if any of them is open */
@@ -2182,7 +2183,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
uchar *packet_end= (uchar *) packet + packet_length - 1;
#endif
Prepared_statement *stmt;
- bool rc;
+ bool error;
DBUG_ENTER("mysql_stmt_execute");
packet+= 9; /* stmt_id + 5 bytes of flags */
@@ -2217,12 +2218,11 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
#endif
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
- rc= stmt->execute(&expanded_query,
- test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
+ error= stmt->execute(&expanded_query,
+ test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
-
- if (rc == 0)
+ if (error == 0)
mysql_log.write(thd, COM_STMT_EXECUTE, "[%lu] %s", stmt->id, thd->query);
DBUG_VOID_RETURN;
@@ -2261,9 +2261,7 @@ void mysql_sql_stmt_execute(THD *thd)
LEX_STRING *name= &lex->prepared_stmt_name;
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
-
DBUG_ENTER("mysql_sql_stmt_execute");
-
DBUG_PRINT("info", ("EXECUTE: %.*s\n", name->length, name->str));
if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
@@ -2408,7 +2406,6 @@ void mysql_stmt_close(THD *thd, char *packet)
/* There is always space for 4 bytes in packet buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
-
DBUG_ENTER("mysql_stmt_close");
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
@@ -2418,7 +2415,7 @@ void mysql_stmt_close(THD *thd, char *packet)
The only way currently a statement can be deallocated when it's
in use is from within Dynamic SQL.
*/
- DBUG_ASSERT(! (stmt->flags & Prepared_statement::IS_IN_USE));
+ DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE));
(void) stmt->deallocate();
DBUG_VOID_RETURN;
@@ -2462,7 +2459,7 @@ void mysql_sql_stmt_close(THD *thd)
mysql_stmt_get_longdata()
thd Thread handle
packet String to append
- packet_length Length of string
+ packet_length Length of string (including end \0)
DESCRIPTION
Get a part of a long data. To make the protocol efficient, we are
@@ -2479,13 +2476,12 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Prepared_statement *stmt;
Item_param *param;
char *packet_end= packet + packet_length - 1;
-
DBUG_ENTER("mysql_stmt_get_longdata");
statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
- if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER)
+ if (packet_length <= MYSQL_LONG_DATA_HEADER)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
DBUG_VOID_RETURN;
@@ -2592,7 +2588,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
param_array(0),
param_count(0),
last_errno(0),
- flags(IS_IN_USE)
+ flags((uint) IS_IN_USE)
{
*last_error= '\0';
}
@@ -2709,7 +2705,7 @@ bool Prepared_statement::set_name(LEX_STRING *name_arg)
bool Prepared_statement::prepare(const char *packet, uint packet_len)
{
- bool rc;
+ bool error;
Statement stmt_backup;
Query_arena *old_stmt_arena;
DBUG_ENTER("Prepared_statement::prepare");
@@ -2739,7 +2735,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
lex_start(thd, (uchar*) thd->query, thd->query_length);
lex->stmt_prepare_mode= TRUE;
- rc= yyparse((void *)thd) || thd->is_fatal_error ||
+ error= yyparse((void *)thd) || thd->is_fatal_error ||
thd->net.report_error || init_param_array(this);
lex->safe_to_cache_query= FALSE;
/*
@@ -2764,10 +2760,10 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
*/
DBUG_ASSERT(thd->free_list == NULL);
- if (rc == 0)
- rc= check_prepared_statement(this, name.str != 0);
+ if (error == 0)
+ error= check_prepared_statement(this, name.str != 0);
- if (rc && lex->sphead)
+ if (error && lex->sphead)
{
delete lex->sphead;
lex->sphead= NULL;
@@ -2777,14 +2773,14 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
thd->restore_backup_statement(this, &stmt_backup);
thd->stmt_arena= old_stmt_arena;
- if (rc == 0)
+ if (error == 0)
{
setup_set_params();
init_stmt_after_parse(lex);
state= Query_arena::PREPARED;
- flags&= ~IS_IN_USE;
+ flags&= ~ (uint) IS_IN_USE;
}
- DBUG_RETURN(rc);
+ DBUG_RETURN(error);
}
/*
@@ -2806,6 +2802,10 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
Preconditions, postconditions.
------------------------------
See the comment for Prepared_statement::prepare().
+
+ RETURN
+ FALSE ok
+ TRUE Error
*/
bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
@@ -2813,7 +2813,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
Statement stmt_backup;
Query_arena *old_stmt_arena;
Item *old_free_list;
- bool rc= TRUE;
+ bool error= TRUE;
statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
@@ -2823,7 +2823,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
my_message(last_errno, last_error, MYF(0));
return TRUE;
}
- if (flags & IS_IN_USE)
+ if (flags & (uint) IS_IN_USE)
{
my_error(ER_PS_NO_RECURSION, MYF(0));
return TRUE;
@@ -2885,13 +2885,14 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
reinit_stmt_before_use(thd, lex);
thd->protocol= protocol; /* activate stmt protocol */
- rc= open_cursor ? mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
- &result, &cursor) :
- mysql_execute_command(thd);
+ error= (open_cursor ?
+ mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
+ &result, &cursor) :
+ mysql_execute_command(thd));
thd->protocol= &thd->protocol_simple; /* use normal protocol */
/* Assert that if an error, no cursor is open */
- DBUG_ASSERT(! (rc && cursor));
+ DBUG_ASSERT(! (error && cursor));
if (! cursor)
{
@@ -2906,8 +2907,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
state= Query_arena::EXECUTED;
error:
- flags&= ~IS_IN_USE;
- return rc;
+ flags&= ~ (uint) IS_IN_USE;
+ return error;
}
@@ -2917,7 +2918,7 @@ bool Prepared_statement::deallocate()
{
/* We account deallocate in the same manner as mysql_stmt_close */
statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
- if (flags & IS_IN_USE)
+ if (flags & (uint) IS_IN_USE)
{
my_error(ER_PS_NO_RECURSION, MYF(0));
return TRUE;
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 154e828b47e..80fcb973028 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -134,6 +134,8 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
{
TABLE_LIST *ren_table,*new_table;
frm_type_enum frm_type;
+ db_type table_type;
+
DBUG_ENTER("rename_tables");
for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
@@ -166,13 +168,12 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
reg_ext);
unpack_filename(name, name);
- frm_type= mysql_frm_type(name);
+ frm_type= mysql_frm_type(thd, name, &table_type);
switch (frm_type)
{
case FRMTYPE_TABLE:
{
- db_type table_type;
- if ((table_type= get_table_type(thd, name)) == DB_TYPE_UNKNOWN)
+ if (table_type == DB_TYPE_UNKNOWN)
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
else
rc= mysql_rename_table(table_type, ren_table->db, old_alias,
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 28b0ae8c78e..b5d12c0d2d2 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -373,6 +373,11 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
goto err;
}
+ /*
+ Call readers_addref before opening log to track count
+ of binlog readers
+ */
+ mysql_bin_log.readers_addref();
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0)
{
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
@@ -570,7 +575,8 @@ impossible position";
goto err;
if (!(flags & BINLOG_DUMP_NON_BLOCK) &&
- mysql_bin_log.is_active(log_file_name))
+ mysql_bin_log.is_active(log_file_name) &&
+ !mysql_bin_log.is_reset_pending())
{
/*
Block until there is more data in the log
@@ -684,6 +690,13 @@ impossible position";
{
bool loop_breaker = 0;
// need this to break out of the for loop from switch
+
+ // if we are going to switch log file anyway, close current log first
+ end_io_cache(&log);
+ (void) my_close(file, MYF(MY_WME));
+ // decrease reference count of binlog readers
+ mysql_bin_log.readers_release();
+
thd->proc_info = "Finished reading one binlog; switching to next binlog";
switch (mysql_bin_log.find_next_log(&linfo, 1)) {
case LOG_INFO_EOF:
@@ -692,16 +705,25 @@ impossible position";
case 0:
break;
default:
+ // need following call to do release on err label
+ mysql_bin_log.readers_addref();
errmsg = "could not find next log";
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err;
}
- if (loop_breaker)
- break;
+ if (loop_breaker)
+ {
+ // need following call to do release on end label
+ mysql_bin_log.readers_addref();
+ break;
+ }
- end_io_cache(&log);
- (void) my_close(file, MYF(MY_WME));
+ /*
+ Call readers_addref before opening log to track count
+ of binlog readers
+ */
+ mysql_bin_log.readers_addref();
/*
Call fake_rotate_event() in case the previous log (the one which
@@ -734,6 +756,8 @@ end:
end_io_cache(&log);
(void)my_close(file, MYF(MY_WME));
+ // decrease reference count of binlog readers
+ mysql_bin_log.readers_release();
send_eof(thd);
thd->proc_info = "Waiting to finalize termination";
@@ -760,6 +784,9 @@ err:
pthread_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
(void) my_close(file, MYF(MY_WME));
+ // decrease reference count of binlog readers
+ mysql_bin_log.readers_release();
+
my_message(my_errno, errmsg, MYF(0));
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a02a61b7a86..360b161a78a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -102,8 +102,6 @@ static COND *optimize_cond(JOIN *join, COND *conds,
List<TABLE_LIST> *join_list,
Item::cond_result *cond_value);
static bool resolve_nested_join (TABLE_LIST *table);
-static COND *remove_eq_conds(THD *thd, COND *cond,
- Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
@@ -537,6 +535,9 @@ JOIN::optimize()
DBUG_RETURN(0);
optimized= 1;
+ if (thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS)
+ thd->status_var.last_query_cost= 0.0;
+
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
/* select_limit is used to decide if we are likely to scan the whole table */
@@ -822,6 +823,7 @@ JOIN::optimize()
{
order=0; // The output has only one row
simple_order=1;
+ select_distinct= 0; // No need in distinct for 1 row
}
calc_group_buffer(this, group_list);
@@ -1167,18 +1169,21 @@ JOIN::save_join_tab()
void
JOIN::exec()
{
+ List<Item> *columns_list= &fields_list;
int tmp_error;
DBUG_ENTER("JOIN::exec");
error= 0;
if (procedure)
{
- if (procedure->change_columns(fields_list) ||
- result->prepare(fields_list, unit))
+ procedure_fields_list= fields_list;
+ if (procedure->change_columns(procedure_fields_list) ||
+ result->prepare(procedure_fields_list, unit))
{
thd->limit_found_rows= thd->examined_row_count= 0;
DBUG_VOID_RETURN;
}
+ columns_list= &procedure_fields_list;
}
(void) result->prepare2(); // Currently, this cannot fail.
@@ -1189,7 +1194,7 @@ JOIN::exec()
(zero_result_cause?zero_result_cause:"No tables used"));
else
{
- result->send_fields(fields_list,
+ result->send_fields(*columns_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
/*
We have to test for 'conds' here as the WHERE may not be constant
@@ -1200,9 +1205,9 @@ JOIN::exec()
(!conds || conds->val_int()) &&
(!having || having->val_int()))
{
- if (do_send_rows && (procedure ? (procedure->send_row(fields_list) ||
- procedure->end_of_records())
- : result->send_data(fields_list)))
+ if (do_send_rows &&
+ (procedure ? (procedure->send_row(procedure_fields_list) ||
+ procedure->end_of_records()) : result->send_data(fields_list)))
error= 1;
else
{
@@ -1226,7 +1231,8 @@ JOIN::exec()
if (zero_result_cause)
{
- (void) return_zero_rows(this, result, select_lex->leaf_tables, fields_list,
+ (void) return_zero_rows(this, result, select_lex->leaf_tables,
+ *columns_list,
send_row_on_empty_set(),
select_options,
zero_result_cause,
@@ -1376,7 +1382,7 @@ JOIN::exec()
DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */
- curr_join->join_free(0);
+ curr_join->join_free();
if (make_simple_join(curr_join, curr_tmp_table))
DBUG_VOID_RETURN;
calc_group_buffer(curr_join, group_list);
@@ -1477,7 +1483,7 @@ JOIN::exec()
if (curr_tmp_table->distinct)
curr_join->select_distinct=0; /* Each row is unique */
- curr_join->join_free(0); /* Free quick selects */
+ curr_join->join_free(); /* Free quick selects */
if (curr_join->select_distinct && ! curr_join->group_list)
{
thd->proc_info="Removing duplicates";
@@ -1676,7 +1682,8 @@ JOIN::exec()
{
thd->proc_info="Sending data";
DBUG_PRINT("info", ("%s", thd->proc_info));
- result->send_fields(*curr_fields_list,
+ result->send_fields((procedure ? curr_join->procedure_fields_list :
+ *curr_fields_list),
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
error= do_select(curr_join, curr_fields_list, NULL, procedure);
thd->limit_found_rows= curr_join->send_records;
@@ -2486,11 +2493,11 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
and use them in equality propagation process (see details in
OptimizerKBAndTodo)
*/
- if ((cond->functype() == Item_func::BETWEEN) &&
- value[0]->eq(value[1], field->binary()))
- eq_func= TRUE;
- else
+ if ((cond->functype() != Item_func::BETWEEN) ||
+ ((Item_func_between*) cond)->negated ||
+ !value[0]->eq(value[1], field->binary()))
return;
+ eq_func= TRUE;
}
if (field->result_type() == STRING_RESULT)
@@ -5734,33 +5741,88 @@ void JOIN_TAB::cleanup()
}
-void JOIN::join_free(bool full)
+/*
+ Partially cleanup JOIN after it has executed: close index or rnd read
+ (table cursors), free quick selects.
+
+ DESCRIPTION
+ This function is called in the end of execution of a JOIN, before the used
+ tables are unlocked and closed.
+
+ For a join that is resolved using a temporary table, the first sweep is
+ performed against actual tables and an intermediate result is inserted
+ into the temprorary table.
+ The last sweep is performed against the temporary table. Therefore,
+ the base tables and associated buffers used to fill the temporary table
+ are no longer needed, and this function is called to free them.
+
+ For a join that is performed without a temporary table, this function
+ is called after all rows are sent, but before EOF packet is sent.
+
+ For a simple SELECT with no subqueries this function performs a full
+ cleanup of the JOIN and calls mysql_unlock_read_tables to free used base
+ tables.
+
+ If a JOIN is executed for a subquery or if it has a subquery, we can't
+ do the full cleanup and need to do a partial cleanup only.
+ o If a JOIN is not the top level join, we must not unlock the tables
+ because the outer select may not have been evaluated yet, and we
+ can't unlock only selected tables of a query.
+
+ o Additionally, if this JOIN corresponds to a correlated subquery, we
+ should not free quick selects and join buffers because they will be
+ needed for the next execution of the correlated subquery.
+
+ o However, if this is a JOIN for a [sub]select, which is not
+ a correlated subquery itself, but has subqueries, we can free it
+ fully and also free JOINs of all its subqueries. The exception
+ is a subquery in SELECT list, e.g:
+ SELECT a, (select max(b) from t1) group by c
+ This subquery will not be evaluated at first sweep and its value will
+ not be inserted into the temporary table. Instead, it's evaluated
+ when selecting from the temporary table. Therefore, it can't be freed
+ here even though it's not correlated.
+*/
+
+void JOIN::join_free()
{
SELECT_LEX_UNIT *unit;
SELECT_LEX *sl;
- DBUG_ENTER("JOIN::join_free");
-
/*
Optimization: if not EXPLAIN and we are done with the JOIN,
free all tables.
*/
- full= full || (!select_lex->uncacheable && !thd->lex->describe);
+ bool full= (!select_lex->uncacheable && !thd->lex->describe);
+ bool can_unlock= full;
+ DBUG_ENTER("JOIN::join_free");
cleanup(full);
for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
for (sl= unit->first_select(); sl; sl= sl->next_select())
{
- JOIN *join= sl->join;
- if (join)
- join->join_free(full);
+ Item_subselect *subselect= sl->master_unit()->item;
+ bool full_local= full && (!subselect || subselect->is_evaluated());
+ /*
+ If this join is evaluated, we can fully clean it up and clean up all
+ its underlying joins even if they are correlated -- they will not be
+ used any more anyway.
+ If this join is not yet evaluated, we still must clean it up to
+ close its table cursors -- it may never get evaluated, as in case of
+ ... HAVING FALSE OR a IN (SELECT ...))
+ but all table cursors must be closed before the unlock.
+ */
+ sl->cleanup_all_joins(full_local);
+ /* Can't unlock if at least one JOIN is still needed */
+ can_unlock= can_unlock && full_local;
}
/*
We are not using tables anymore
Unlock all tables. We may be in an INSERT .... SELECT statement.
*/
- if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) &&
+ if (can_unlock && lock && thd->lock &&
+ !(select_options & SELECT_NO_UNLOCK) &&
!select_lex->subquery_in_having &&
(select_lex == (thd->lex->unit.fake_select_lex ?
thd->lex->unit.fake_select_lex : &thd->lex->select_lex)))
@@ -5866,7 +5928,7 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
tab->cached_eq_ref_table=1;
if (tab->type == JT_CONST) // We can skip const tables
return (tab->eq_ref_table=1); /* purecov: inspected */
- if (tab->type != JT_EQ_REF)
+ if (tab->type != JT_EQ_REF || tab->table->maybe_null)
return (tab->eq_ref_table=0); // We must use this
Item **ref_item=tab->ref.items;
Item **end=ref_item+tab->ref.key_parts;
@@ -6074,7 +6136,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
DBUG_RETURN(0);
}
- join->join_free(0);
+ join->join_free();
if (send_row)
{
@@ -6269,6 +6331,21 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
{
Item *left_item= ((Item_func*) item)->arguments()[0];
Item *right_item= ((Item_func*) item)->arguments()[1];
+
+ if (left_item->type() == Item::REF_ITEM &&
+ ((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
+ {
+ if (((Item_ref*)left_item)->depended_from)
+ return FALSE;
+ left_item= left_item->real_item();
+ }
+ if (right_item->type() == Item::REF_ITEM &&
+ ((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF)
+ {
+ if (((Item_ref*)right_item)->depended_from)
+ return FALSE;
+ right_item= right_item->real_item();
+ }
if (left_item->type() == Item::FIELD_ITEM &&
right_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from &&
@@ -7410,7 +7487,7 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
COND_FALSE always false ( 1 = 2 )
*/
-static COND *
+COND *
remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
{
if (cond->type() == Item::COND_ITEM)
@@ -7967,7 +8044,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
- if (use_temp_pool)
+ if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
temp_pool_slot = bitmap_lock_set_next(&temp_pool);
if (temp_pool_slot != MY_BIT_NONE) // we got a slot
@@ -8221,7 +8298,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM))
{
- table->file=get_new_handler(table,table->s->db_type= DB_TYPE_MYISAM);
+ table->file= get_new_handler(table, &table->mem_root,
+ table->s->db_type= DB_TYPE_MYISAM);
if (group &&
(param->group_parts > table->file->max_key_parts() ||
param->group_length > table->file->max_key_length()))
@@ -8229,7 +8307,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
{
- table->file=get_new_handler(table,table->s->db_type= DB_TYPE_HEAP);
+ table->file= get_new_handler(table, &table->mem_root,
+ table->s->db_type= DB_TYPE_HEAP);
}
if (table->s->fields)
{
@@ -8816,7 +8895,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
new_table= *table;
new_table.s= &new_table.share_not_to_be_used;
new_table.s->db_type= DB_TYPE_MYISAM;
- if (!(new_table.file= get_new_handler(&new_table,DB_TYPE_MYISAM)))
+ if (!(new_table.file= get_new_handler(&new_table, &new_table.mem_root,
+ DB_TYPE_MYISAM)))
DBUG_RETURN(1); // End of memory
save_proc_info=thd->proc_info;
@@ -9006,7 +9086,11 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
error= (*end_select)(join,join_tab,1);
}
else if (join->send_row_on_empty_set())
- rc= join->result->send_data(*join->fields);
+ {
+ List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
+ fields);
+ rc= join->result->send_data(*columns_list);
+ }
}
else
{
@@ -9031,7 +9115,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
The following will unlock all cursors if the command wasn't an
update command
*/
- join->join_free(0); // Unlock all cursors
+ join->join_free(); // Unlock all cursors
if (join->result->send_eof())
rc= 1; // Don't send error
}
@@ -10039,7 +10123,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
error=0;
if (join->procedure)
- error=join->procedure->send_row(*join->fields);
+ error=join->procedure->send_row(join->procedure_fields_list);
else if (join->do_send_rows)
error=join->result->send_data(*join->fields);
if (error)
@@ -11371,7 +11455,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
ulong total_length= 0;
for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
{
- uint length= (*ptr)->pack_length();
+ uint length= (*ptr)->sort_length();
(*field_length++)= length;
total_length+= length;
}
@@ -11911,11 +11995,16 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
*/
+ thd->lex->current_select->is_item_list_lookup= 1;
if (!order_item->fixed &&
(order_item->fix_fields(thd, order->item) ||
(order_item= *order->item)->check_cols(1) ||
thd->is_fatal_error))
+ {
+ thd->lex->current_select->is_item_list_lookup= 0;
return TRUE; /* Wrong field. */
+ }
+ thd->lex->current_select->is_item_list_lookup= 0;
uint el= all_fields.elements;
all_fields.push_front(order_item); /* Add new field to field list. */
diff --git a/sql/sql_select.h b/sql/sql_select.h
index be51851e760..ec969e51c8d 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -245,6 +245,7 @@ class JOIN :public Sql_alloc
//Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
List<Item> &fields_list; // hold field list passed to mysql_select
+ List<Item> procedure_fields_list;
int error;
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
@@ -359,7 +360,7 @@ class JOIN :public Sql_alloc
the end of execution in order to increase concurrency and reduce
memory consumption.
*/
- void join_free(bool full);
+ void join_free();
/* Cleanup this JOIN, possibly for reuse */
void cleanup(bool full);
void clear();
@@ -524,3 +525,4 @@ bool cp_buffer_from_ref(THD *thd, TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
+COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 24acb1fb6d1..d06b09f9793 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1031,6 +1031,11 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
packet->append(" COMMENT=", 9);
append_unescaped(packet, share->comment, strlen(share->comment));
}
+ if (share->connect_string.length)
+ {
+ packet->append(" CONNECTION=", 12);
+ append_unescaped(packet, share->connect_string.str, share->connect_string.length);
+ }
if (file->raid_type)
{
uint length;
@@ -1283,9 +1288,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thread_info *thd_info;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- Security_context *sctx;
-#endif
time_t now= time(0);
while ((thd_info=thread_infos.get()))
{
@@ -1665,6 +1667,9 @@ static bool show_status_array(THD *thd, const char *wild,
value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
end= longlong10_to_str(*(longlong*) value, buff, 10);
break;
+ case SHOW_NET_COMPRESSION:
+ end= strmov(buff, thd->net.compress ? "ON" : "OFF");
+ break;
case SHOW_UNDEF: // Show never happen
case SHOW_SYS:
break; // Return empty string
@@ -2026,6 +2031,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
Security_context *sctx= thd->security_ctx;
uint derived_tables= lex->derived_tables;
int error= 1;
+ db_type not_used;
Open_tables_state open_tables_state_backup;
DBUG_ENTER("get_all_tables");
@@ -2137,7 +2143,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
my_snprintf(end, len, "/%s%s", file_name, reg_ext);
- switch (mysql_frm_type(path)) {
+ switch (mysql_frm_type(thd, path, &not_used)) {
case FRMTYPE_ERROR:
table->field[3]->store("ERROR", 5, system_charset_info);
break;
@@ -2356,14 +2362,14 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
table->field[7]->store((longlong) file->records, TRUE);
table->field[7]->set_notnull();
}
- table->field[8]->store((longlong) file->mean_rec_length);
- table->field[9]->store((longlong) file->data_file_length);
+ table->field[8]->store((longlong) file->mean_rec_length, TRUE);
+ table->field[9]->store((longlong) file->data_file_length, TRUE);
if (file->max_data_file_length)
{
- table->field[10]->store((longlong) file->max_data_file_length);
+ table->field[10]->store((longlong) file->max_data_file_length, TRUE);
}
- table->field[11]->store((longlong) file->index_file_length);
- table->field[12]->store((longlong) file->delete_length);
+ table->field[11]->store((longlong) file->index_file_length, TRUE);
+ table->field[12]->store((longlong) file->delete_length, TRUE);
if (show_table->found_next_number_field)
{
table->field[13]->store((longlong) file->auto_increment_value, TRUE);
@@ -2582,11 +2588,12 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
is_blob= (field->type() == FIELD_TYPE_BLOB);
if (field->has_charset() || is_blob)
{
- longlong c_octet_len= is_blob ? (longlong) field->max_length() :
- (longlong) field->max_length()/field->charset()->mbmaxlen;
- table->field[8]->store(c_octet_len, TRUE);
+ longlong char_max_len= is_blob ?
+ (longlong) field->max_length() / field->charset()->mbminlen :
+ (longlong) field->max_length() / field->charset()->mbmaxlen;
+ table->field[8]->store(char_max_len, TRUE);
table->field[8]->set_notnull();
- table->field[9]->store((longlong) field->max_length());
+ table->field[9]->store((longlong) field->max_length(), TRUE);
table->field[9]->set_notnull();
}
@@ -2627,7 +2634,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
if (field_length >= 0)
{
- table->field[10]->store((longlong) field_length);
+ table->field[10]->store((longlong) field_length, TRUE);
table->field[10]->set_notnull();
}
if (decimals >= 0)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index a1f2be7e11c..a990cf777d6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -277,6 +277,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
String wrong_tables;
int error;
bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0;
+
DBUG_ENTER("mysql_rm_table_part2");
if (lock_table_names(thd, tables))
@@ -288,6 +289,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
for (table= tables; table; table= table->next_local)
{
char *db=table->db;
+ db_type table_type= DB_TYPE_UNKNOWN;
+
mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL);
if (!close_temporary_table(thd, db, table->table_name))
{
@@ -315,7 +318,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (drop_temporary ||
(access(path,F_OK) &&
ha_create_table_from_engine(thd,db,alias)) ||
- (!drop_view && mysql_frm_type(path) != FRMTYPE_TABLE))
+ (!drop_view &&
+ mysql_frm_type(thd, path, &table_type) != FRMTYPE_TABLE))
{
// Table was not found on disk and table can't be created from engine
if (if_exists)
@@ -328,11 +332,13 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
else
{
char *end;
- db_type table_type= get_table_type(thd, path);
+ if (table_type == DB_TYPE_UNKNOWN)
+ mysql_frm_type(thd, path, &table_type);
*(end=fn_ext(path))=0; // Remove extension for delete
error= ha_delete_table(thd, table_type, path, table->table_name,
!dont_log_query);
- if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
+ if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
+ (if_exists || table_type == DB_TYPE_UNKNOWN))
error= 0;
if (error == HA_ERR_ROW_IS_REFERENCED)
{
@@ -897,8 +903,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->charset= (dup_field->charset ?
dup_field->charset :
create_info->default_table_charset);
- sql_field->length= dup_field->length;
- sql_field->pack_length= dup_field->pack_length;
+ sql_field->length= dup_field->chars_length;
+ sql_field->pack_length= dup_field->pack_length;
sql_field->key_length= dup_field->key_length;
sql_field->create_length_to_internal_length();
sql_field->decimals= dup_field->decimals;
@@ -1207,13 +1213,17 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
column->length*= sql_field->charset->mbmaxlen;
- if (f_is_blob(sql_field->pack_flag))
+ if (f_is_blob(sql_field->pack_flag) ||
+ (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
{
if (!(file->table_flags() & HA_CAN_INDEX_BLOBS))
{
my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
+ if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
+ Field::GEOM_POINT)
+ column->length= 21;
if (!column->length)
{
my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
@@ -1590,7 +1600,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (create_info->row_type == ROW_TYPE_DYNAMIC)
db_options|=HA_OPTION_PACK_RECORD;
alias= table_case_name(create_info, table_name);
- if (!(file=get_new_handler((TABLE*) 0, create_info->db_type)))
+ if (!(file=get_new_handler((TABLE*) 0, thd->mem_root, create_info->db_type)))
{
my_error(ER_OUTOFMEMORY, MYF(0), 128);//128 bytes invented
DBUG_RETURN(TRUE);
@@ -1626,7 +1636,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
}
if (check_partition_info(part_info, part_engine_type,
file, create_info->max_rows))
- DBUG_RETURN(TRUE);
+ goto err;
+
/*
We reverse the partitioning parser and generate a standard format
for syntax stored in frm file.
@@ -1634,7 +1645,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
TRUE,TRUE)))
- DBUG_RETURN(TRUE);
+ goto err;
part_info->part_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
if ((!(file->partition_flags() & HA_CAN_PARTITION)) ||
@@ -1644,7 +1655,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
The handler assigned to the table cannot handle partitioning.
Assign the partition handler as the handler of the table.
*/
- DBUG_PRINT("info", ("db_type= %d, part_flag= %d", create_info->db_type,file->partition_flags()));
+ DBUG_PRINT("info", ("db_type: %d part_flag: %d",
+ create_info->db_type,file->partition_flags()));
delete file;
create_info->db_type= DB_TYPE_PARTITION_DB;
if (!(file= get_ha_partition(part_info)))
@@ -1702,7 +1714,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
- goto no_err;
+ error= 0;
+ goto err;
}
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
goto err;
@@ -1717,7 +1730,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- goto end;
+ goto unlock_and_end;
}
}
@@ -1741,7 +1754,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (create_if_not_exists)
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- goto end;
+ goto unlock_and_end;
}
}
@@ -1755,14 +1768,14 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (rea_create_table(thd, path, db, table_name,
create_info, fields, key_count,
key_info_buffer, file))
- goto end;
+ goto unlock_and_end;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
/* Open table and put in temporary table list */
if (!(open_temporary_table(thd, path, db, table_name, 1)))
{
(void) rm_temporary_table(create_info->db_type, path);
- goto end;
+ goto unlock_and_end;
}
thd->tmp_table_used= 1;
}
@@ -1772,29 +1785,24 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
+
error= FALSE;
- goto end;
+unlock_and_end:
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ start_waiting_global_read_lock(thd);
+
+err:
+ thd->proc_info="After create";
+ delete file;
+ DBUG_RETURN(error);
warn:
- error= 0;
+ error= FALSE;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
create_info->table_existed= 1; // Mark that table existed
-
-end:
- VOID(pthread_mutex_unlock(&LOCK_open));
- start_waiting_global_read_lock(thd);
- delete file;
- thd->proc_info="After create";
- DBUG_RETURN(error);
-
-err:
- delete file;
- DBUG_RETURN(TRUE);
-no_err:
- delete file;
- DBUG_RETURN(FALSE);
+ goto unlock_and_end;
}
/*
@@ -1946,10 +1954,12 @@ mysql_rename_table(enum db_type base,
const char *new_db,
const char *new_name)
{
+ THD *thd= current_thd;
char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN];
char *from_base= from, *to_base= to;
char tmp_name[NAME_LEN+1];
- handler *file=(base == DB_TYPE_UNKNOWN ? 0 : get_new_handler((TABLE*) 0, base));
+ handler *file= (base == DB_TYPE_UNKNOWN ? 0 :
+ get_new_handler((TABLE*) 0, thd->mem_root, base));
int error=0;
DBUG_ENTER("mysql_rename_table");
@@ -2095,8 +2105,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
{
char* backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->table_name;
- char* db = thd->db ? thd->db : table->db;
+ char* table_name= table->table_name;
+ char* db= table->db;
if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
reg_ext))
@@ -2132,12 +2142,15 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
Now we should be able to open the partially restored table
to finish the restore in the handler later on
*/
- if (!(table->table = reopen_name_locked_table(thd, table)))
+ pthread_mutex_lock(&LOCK_open);
+ if (reopen_name_locked_table(thd, table))
{
- pthread_mutex_lock(&LOCK_open);
unlock_table_name(thd, table);
pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(send_check_errmsg(thd, table, "restore",
+ "Failed to open partially restored table"));
}
+ pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(0);
}
@@ -2234,12 +2247,16 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
Now we should be able to open the partially repaired table
to finish the repair in the handler later on.
*/
- if (!(table_list->table = reopen_name_locked_table(thd, table_list)))
+ pthread_mutex_lock(&LOCK_open);
+ if (reopen_name_locked_table(thd, table_list))
{
- pthread_mutex_lock(&LOCK_open);
unlock_table_name(thd, table_list);
pthread_mutex_unlock(&LOCK_open);
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed to open partially repaired table");
+ goto end;
}
+ pthread_mutex_unlock(&LOCK_open);
end:
if (table == &tmp_table)
@@ -2748,6 +2765,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
char *src_table= table_ident->table.str;
int err;
bool res= TRUE;
+ db_type not_used;
+
TABLE_LIST src_tables_list;
DBUG_ENTER("mysql_create_like_table");
src_db= table_ident->db.str ? table_ident->db.str : thd->db;
@@ -2795,7 +2814,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
/*
create like should be not allowed for Views, Triggers, ...
*/
- if (mysql_frm_type(src_path) != FRMTYPE_TABLE)
+ if (mysql_frm_type(thd, src_path, &not_used) != FRMTYPE_TABLE)
{
my_error(ER_WRONG_OBJECT, MYF(0), src_db, src_table, "BASE TABLE");
goto err;
@@ -3867,15 +3886,14 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type= table->s->row_type;
- DBUG_PRINT("info", ("old type: %d new type: %d", old_db_type, new_db_type));
- if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED)
- || ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
+ DBUG_PRINT("info", ("old type: %d new type: %d", old_db_type, new_db_type));
+ if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) ||
+ ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
{
DBUG_PRINT("info", ("doesn't support alter"));
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
DBUG_RETURN(TRUE);
}
- DBUG_PRINT("info", ("supports alter"));
thd->proc_info="setup";
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index df8de59508d..dbad8dcffb5 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -103,8 +103,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig);
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
{
TABLE *table;
- bool result= 0;
-
+ bool result= TRUE;
DBUG_ENTER("mysql_create_or_drop_trigger");
/*
@@ -119,9 +118,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
/* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0);
- if (!(table= open_ltable(thd, tables, tables->lock_type)))
- DBUG_RETURN(TRUE);
-
/*
TODO: We should check if user has TRIGGER privilege for table here.
Now we just require SUPER privilege for creating/dropping because
@@ -131,28 +127,24 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
/*
- We do not allow creation of triggers on temporary tables. We also don't
- allow creation of triggers on views but fulfilment of this restriction
- is guaranteed by open_ltable(). It is better to have this check here
- than do it in Table_triggers_list::create_trigger() and mess with table
- cache.
+ There is no DETERMINISTIC clause for triggers, so can't check it.
+ But a trigger can in theory be used to do nasty things (if it supported
+ DROP for example) so we do the check for privileges. For now there is
+ already a stronger test right above; but when this stronger test will
+ be removed, the test below will hold.
*/
- if (table->s->tmp_table != NO_TMP_TABLE)
+ if (!trust_routine_creators && mysql_bin_log.is_open() &&
+ !(thd->security_ctx->master_access & SUPER_ACL))
{
- my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0));
DBUG_RETURN(TRUE);
}
- if (!table->triggers)
+ /* We do not allow creation of triggers on temporary tables. */
+ if (create && find_temporary_table(thd, tables->db, tables->table_name))
{
- if (!create)
- {
- my_message(ER_TRG_DOES_NOT_EXIST, ER(ER_TRG_DOES_NOT_EXIST), MYF(0));
- DBUG_RETURN(TRUE);
- }
-
- if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table)))
- DBUG_RETURN(TRUE);
+ my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ DBUG_RETURN(TRUE);
}
/*
@@ -161,31 +153,41 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
again until we are done. (Acquiring LOCK_open is not enough because
global read lock is held without helding LOCK_open).
*/
- if (wait_if_global_read_lock(thd, 0, 0))
+ if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(TRUE);
- /*
- There is no DETERMINISTIC clause for triggers, so can't check it.
- But a trigger can in theory be used to do nasty things (if it supported
- DROP for example) so we do the check for privileges. For now there is
- already a stronger test above (see start of the function); but when this
- stronger test will be removed, the test below will hold.
- */
- if (!trust_routine_creators && mysql_bin_log.is_open() &&
- !(thd->security_ctx->master_access & SUPER_ACL))
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ if (lock_table_names(thd, tables))
+ goto end;
+
+ /* We also don't allow creation of triggers on views. */
+ tables->required_type= FRMTYPE_TABLE;
+
+ if (reopen_name_locked_table(thd, tables))
{
- my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,
- ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0));
- DBUG_RETURN(TRUE);
+ unlock_table_name(thd, tables);
+ goto end;
+ }
+ table= tables->table;
+
+ if (!table->triggers)
+ {
+ if (!create)
+ {
+ my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
+ goto end;
+ }
+
+ if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table)))
+ goto end;
}
- VOID(pthread_mutex_lock(&LOCK_open));
result= (create ?
table->triggers->create_trigger(thd, tables):
table->triggers->drop_trigger(thd, tables));
- /* It is sensible to invalidate table in any case */
- close_cached_table(thd, table);
+end:
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 951248e8cd8..dee88af7d83 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -720,3 +720,17 @@ bool st_select_lex::cleanup()
DBUG_RETURN(error);
}
+
+void st_select_lex::cleanup_all_joins(bool full)
+{
+ SELECT_LEX_UNIT *unit;
+ SELECT_LEX *sl;
+
+ if (join)
+ join->cleanup(full);
+
+ for (unit= first_inner_unit(); unit; unit= unit->next_unit())
+ for (sl= unit->first_select(); sl; sl= sl->next_select())
+ sl->cleanup_all_joins(full);
+}
+
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 72a8eef9a55..41961b66f0f 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -121,8 +121,9 @@ int mysql_update(THD *thd,
bool safe_update= thd->options & OPTION_SAFE_UPDATES;
bool used_key_is_modified, transactional_table, will_batch;
int res;
- int error=0, loc_error;
- uint used_index, dup_key_found;
+ int error, loc_error;
+ uint used_index= MAX_KEY, dup_key_found;
+ bool need_sort= TRUE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
@@ -194,6 +195,7 @@ int mysql_update(THD *thd,
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
+ table_list->register_want_access(want_privilege);
#endif
/*
Indicate that the set of fields is to be updated by passing 2 for
@@ -233,11 +235,18 @@ int mysql_update(THD *thd,
DBUG_RETURN(1); /* purecov: inspected */
}
+ if (conds)
+ {
+ Item::cond_result cond_value;
+ conds= remove_eq_conds(thd, conds, &cond_value);
+ if (cond_value == Item::COND_FALSE)
+ limit= 0; // Impossible WHERE
+ }
// Don't count on usage of 'only index' when calculating which key to use
table->used_keys.clear_all();
select= make_select(table, 0, 0, conds, 0, &error);
- if (error ||
- (select && select->check_quick(thd, safe_update, limit)) || !limit)
+ if (error || !limit ||
+ (select && select->check_quick(thd, safe_update, limit)))
{
delete select;
free_underlaid_joins(thd, select_lex);
@@ -248,6 +257,11 @@ int mysql_update(THD *thd,
send_ok(thd); // No matching records
DBUG_RETURN(0);
}
+ if (!select && limit != HA_POS_ERROR)
+ {
+ if ((used_index= get_index_for_order(table, order, limit)) != MAX_KEY)
+ need_sort= FALSE;
+ }
/* If running in safe sql mode, don't allow updates without keys */
if (table->quick_keys.is_clear_all())
{
@@ -268,10 +282,14 @@ int mysql_update(THD *thd,
used_key_is_modified= (!select->quick->unique_key_range() &&
select->quick->check_if_keys_used(&fields));
}
- else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
- used_key_is_modified=check_if_key_used(table, used_index, fields);
else
- used_key_is_modified=0;
+ {
+ used_key_is_modified= 0;
+ if (used_index == MAX_KEY) // no index for sort order
+ used_index= table->file->key_used_on_scan;
+ if (used_index != MAX_KEY)
+ used_key_is_modified= check_if_key_used(table, used_index, fields);
+ }
#ifdef HAVE_PARTITION_DB
if (used_key_is_modified || order ||
@@ -291,7 +309,8 @@ int mysql_update(THD *thd,
table->file->extra(HA_EXTRA_KEYREAD);
}
- if (order)
+ /* note: can actually avoid sorting below.. */
+ if (order && (need_sort || used_key_is_modified))
{
/*
Doing an ORDER BY; Let filesort find and sort the rows we are going
@@ -301,6 +320,7 @@ int mysql_update(THD *thd,
SORT_FIELD *sortorder;
ha_rows examined_rows;
+ used_index= MAX_KEY; // For call to init_read_record()
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (!(sortorder=make_unireg_sortorder(order, &length)) ||
@@ -335,7 +355,10 @@ int mysql_update(THD *thd,
/* If quick select is used, initialize it before retrieving rows. */
if (select && select->quick && select->quick->reset())
goto err;
- init_read_record(&info,thd,table,select,0,1);
+ if (used_index == MAX_KEY || (select && select->quick))
+ init_read_record(&info,thd,table,select,0,1);
+ else
+ init_read_record_idx(&info, thd, table, 1, used_index);
thd->proc_info="Searching rows for update";
uint tmp_limit= limit;
@@ -364,6 +387,7 @@ int mysql_update(THD *thd,
error= 1; // Aborted
limit= tmp_limit;
end_read_record(&info);
+
/* Change select to use tempfile */
if (select)
{
@@ -671,6 +695,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
+ table_list->register_want_access(SELECT_ACL);
#endif
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
@@ -946,9 +971,6 @@ bool mysql_multi_update(THD *thd,
multi_update *result;
DBUG_ENTER("mysql_multi_update");
- if (mysql_multi_update_prepare(thd))
- DBUG_RETURN(TRUE);
-
if (!(result= new multi_update(table_list,
thd->lex->select_lex.leaf_tables,
fields, values,
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index f956d9d4928..71c5d198b27 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -643,7 +643,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
view->query.length= str.length()-1; // we do not need last \0
view->source.str= thd->lex->create_view_select_start;
view->source.length= (thd->query_length -
- (thd->lex->create_view_select_start - thd->query));
+ (thd->lex->create_view_select_start -
+ thd->lex->create_view_start));
view->file_version= 1;
view->calc_md5(md5);
view->md5.str= md5;
@@ -721,44 +722,59 @@ loop_out:
}
+
/*
read VIEW .frm and create structures
SYNOPSIS
mysql_make_view()
- parser - parser object;
- table - TABLE_LIST structure for filling
+ thd Thread handler
+ parser parser object
+ table TABLE_LIST structure for filling
RETURN
0 ok
1 error
*/
-my_bool
-mysql_make_view(File_parser *parser, TABLE_LIST *table)
+bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
{
+ SELECT_LEX *end, *view_select;
+ LEX *old_lex, *lex;
+ Query_arena *arena, backup;
+ int res;
+ bool result;
DBUG_ENTER("mysql_make_view");
- DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
+ DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
if (table->view)
{
+ /*
+ It's an execution of a PS/SP and the view has already been unfolded
+ into a list of used tables. Now we only need to update the information
+ about granted privileges in the view tables with the actual data
+ stored in MySQL privilege system. We don't need to restore the
+ required privileges (by calling register_want_access) because they has
+ not changed since PREPARE or the previous execution: the only case
+ when this information is changed is execution of UPDATE on a view, but
+ the original want_access is restored in its end.
+ */
+ if (!table->prelocking_placeholder && table->prepare_security(thd))
+ {
+ DBUG_RETURN(1);
+ }
DBUG_PRINT("info",
("VIEW %s.%s is already processed on previous PS/SP execution",
table->view_db.str, table->view_name.str));
DBUG_RETURN(0);
}
- SELECT_LEX *end;
- THD *thd= current_thd;
- LEX *old_lex= thd->lex, *lex;
- SELECT_LEX *view_select;
- int res= 0;
-
/*
For now we assume that tables will not be changed during PS life (it
will be TRUE as far as we make new table cache).
*/
- Query_arena *arena= thd->stmt_arena, backup;
+ old_lex= thd->lex;
+ arena= thd->stmt_arena;
if (arena->is_conventional())
arena= 0;
else
@@ -768,7 +784,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
if (!table->timestamp.str)
table->timestamp.str= table->timestamp_buffer;
/* prepare default values for old format */
- table->view_suid= 1;
+ table->view_suid= TRUE;
table->definer.user.str= table->definer.host.str= 0;
table->definer.user.length= table->definer.host.length= 0;
@@ -879,6 +895,10 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
goto err;
}
+
+ if (!(table->view_tables=
+ (List<TABLE_LIST>*) new(thd->mem_root) List<TABLE_LIST>))
+ goto err;
/*
mark to avoid temporary table using and put view reference and find
last view table
@@ -889,6 +909,22 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
tbl->skip_temporary= 1;
tbl->belong_to_view= top_view;
+ tbl->referencing_view= table;
+ /*
+ First we fill want_privilege with SELECT_ACL (this is needed for the
+ tables which belongs to view subqueries and temporary table views,
+ then for the merged view underlying tables we will set wanted
+ privileges of top_view
+ */
+ tbl->grant.want_privilege= SELECT_ACL;
+ /*
+ After unfolding the view we lose the list of tables referenced in it
+ (we will have only a list of underlying tables in case of MERGE
+ algorithm, which does not include the tables referenced from
+ subqueries used in view definition).
+ Let's build a list of all tables referenced in the view.
+ */
+ table->view_tables->push_back(tbl);
}
/*
@@ -914,16 +950,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
}
/*
- Let us set proper lock type for tables of the view's main select
- since we may want to perform update or insert on view. This won't
- work for view containing union. But this is ok since we don't
- allow insert and update on such views anyway.
- */
- if (!lex->select_lex.next_select())
- for (tbl= lex->select_lex.get_table_list(); tbl; tbl= tbl->next_local)
- tbl->lock_type= table->lock_type;
-
- /*
If we are opening this view as part of implicit LOCK TABLES, then
this view serves as simple placeholder and we should not continue
further processing.
@@ -931,7 +957,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
if (table->prelocking_placeholder)
goto ok2;
- old_lex->derived_tables|= DERIVED_VIEW;
+ old_lex->derived_tables|= (DERIVED_VIEW | lex->derived_tables);
/* move SQL_NO_CACHE & Co to whole query */
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
@@ -940,6 +966,37 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
if (view_select->options & OPTION_TO_QUERY_CACHE)
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+ if (table->view_suid)
+ {
+ /*
+ Prepare a security context to check underlying objects of the view
+ */
+ Security_context *save_security_ctx= thd->security_ctx;
+ if (!(table->view_sctx= (Security_context *)
+ thd->stmt_arena->alloc(sizeof(Security_context))))
+ goto err;
+ /* Assign the context to the tables referenced in the view */
+ for (tbl= view_tables; tbl; tbl= tbl->next_global)
+ tbl->security_ctx= table->view_sctx;
+ /* assign security context to SELECT name resolution contexts of view */
+ for(SELECT_LEX *sl= lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ sl->context.security_ctx= table->view_sctx;
+ }
+
+ /*
+ Setup an error processor to hide error messages issued by stored
+ routines referenced in the view
+ */
+ for (SELECT_LEX *sl= lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ sl->context.error_processor= &view_error_processor;
+ sl->context.error_processor_data= (void *)table;
+ }
+
/*
check MERGE algorithm ability
- algorithm is not explicit TEMPORARY TABLE
@@ -961,24 +1018,28 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->updatable= (table->updatable_view != 0);
table->effective_with_check=
old_lex->get_effective_with_check(table);
+ table->merge_underlying_list= view_tables;
+ /*
+ Let us set proper lock type for tables of the view's main select
+ since we may want to perform update or insert on view. This won't
+ work for view containing union. But this is ok since we don't
+ allow insert and update on such views anyway.
+
+ Also we fill correct wanted privileges.
+ */
+ for (tbl= table->merge_underlying_list; tbl; tbl= tbl->next_local)
+ {
+ tbl->lock_type= table->lock_type;
+ tbl->grant.want_privilege= top_view->grant.orig_want_privilege;
+ }
/* prepare view context */
- lex->select_lex.context.resolve_in_table_list_only(table->ancestor=
- view_tables);
+ lex->select_lex.context.resolve_in_table_list_only(view_tables);
lex->select_lex.context.outer_context= 0;
lex->select_lex.context.select_lex= table->select_lex;
lex->select_lex.select_n_having_items+=
table->select_lex->select_n_having_items;
- /* do not check privileges & hide errors for view underlyings */
- for (SELECT_LEX *sl= lex->all_selects_list;
- sl;
- sl= sl->next_select_in_list())
- {
- sl->context.check_privileges= FALSE;
- sl->context.error_processor= &view_error_processor;
- sl->context.error_processor_data= (void *)table;
- }
/*
Tables of the main select of the view should be marked as belonging
to the same select as original view (again we can use LEX::select_lex
@@ -1011,7 +1072,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
}
}
- /* Store WHERE clause for post-processing in setup_ancestor */
+ /* Store WHERE clause for post-processing in setup_underlying */
table->where= view_select->where;
/*
Add subqueries units to SELECT into which we merging current view.
@@ -1072,20 +1133,21 @@ ok:
(st_select_lex_node**)&old_lex->all_selects_list;
ok2:
- if (arena)
- thd->restore_active_arena(arena, &backup);
if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used)
old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
- thd->lex= old_lex;
- DBUG_RETURN(0);
+ result= !table->prelocking_placeholder && table->prepare_security(thd);
-err:
+end:
if (arena)
thd->restore_active_arena(arena, &backup);
+ thd->lex= old_lex;
+ DBUG_RETURN(result);
+
+err:
delete table->view;
table->view= 0; // now it is not VIEW placeholder
- thd->lex= old_lex;
- DBUG_RETURN(1);
+ result= 1;
+ goto end;
}
@@ -1109,6 +1171,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
char path[FN_REFLEN];
TABLE_LIST *view;
bool type= 0;
+ db_type not_used;
for (view= views; view; view= view->next_local)
{
@@ -1116,7 +1179,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
view->table_name, reg_ext, NullS);
(void) unpack_filename(path, path);
VOID(pthread_mutex_lock(&LOCK_open));
- if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW)))
+ if (access(path, F_OK) ||
+ (type= (mysql_frm_type(thd, path, &not_used) != FRMTYPE_VIEW)))
{
char name[FN_REFLEN];
my_snprintf(name, sizeof(name), "%s.%s", view->db, view->table_name);
@@ -1163,24 +1227,36 @@ err:
FRMTYPE_VIEW view
*/
-frm_type_enum mysql_frm_type(char *path)
+frm_type_enum mysql_frm_type(THD *thd, char *path, db_type *dbt)
{
File file;
- char header[10]; //"TYPE=VIEW\n" it is 10 characters
- int length;
+ uchar header[10]; //"TYPE=VIEW\n" it is 10 characters
+ int error;
DBUG_ENTER("mysql_frm_type");
+ *dbt= DB_TYPE_UNKNOWN;
+
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
- {
DBUG_RETURN(FRMTYPE_ERROR);
- }
- length= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME));
+ error= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME | MY_NABP));
my_close(file, MYF(MY_WME));
- if (length == (int) MY_FILE_ERROR)
+
+ if (error)
DBUG_RETURN(FRMTYPE_ERROR);
- if (length < (int) sizeof(header) ||
- !strncmp(header, "TYPE=VIEW\n", sizeof(header)))
+ if (!strncmp((char*) header, "TYPE=VIEW\n", sizeof(header)))
DBUG_RETURN(FRMTYPE_VIEW);
+
+ /*
+ This is just a check for DB_TYPE. We'll return default unknown type
+ if the following test is true (arg #3). This should not have effect
+ on return value from this function (default FRMTYPE_TABLE)
+ */
+ if (header[0] != (uchar) 254 || header[1] != 1 ||
+ (header[2] != FRM_VER && header[2] != FRM_VER+1 &&
+ (header[2] < FRM_VER+3 || header[2] > FRM_VER+4)))
+ DBUG_RETURN(FRMTYPE_TABLE);
+
+ *dbt= ha_checktype(thd, (enum db_type) (uint) *(header + 3), 0, 0);
DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table
}
@@ -1427,7 +1503,7 @@ mysql_rename_view(THD *thd,
/* get view definition and source */
if (parser->parse((gptr)&view_def, thd->mem_root, view_parameters,
- sizeof(view_parameters)/sizeof(view_parameters[0])-1))
+ array_elements(view_parameters)-1))
goto err;
/* rename view and it's backups */
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 4cc9eb454fb..cd61d7e9e71 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -19,7 +19,7 @@
bool mysql_create_view(THD *thd,
enum_view_create_mode mode);
-my_bool mysql_make_view(File_parser *parser, TABLE_LIST *table);
+bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table);
bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);
@@ -27,7 +27,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST * view);
bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view);
-frm_type_enum mysql_frm_type(char *path);
+frm_type_enum mysql_frm_type(THD *thd, char *path, db_type *dbt);
int view_checksum(THD *thd, TABLE_LIST *view);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 77c1a37e16e..e6c0216ef3a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -670,7 +670,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token YEAR_SYM
%token ZEROFILL
-%left JOIN_SYM
+%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT
/* A dummy token to force the priority of table_ref production in a join. */
%left TABLE_REF_PRIORITY
%left SET_VAR
@@ -1279,6 +1279,7 @@ create:
THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
+ lex->create_view_start= thd->query;
/* first table in list is target VIEW name */
if (!lex->select_lex.add_table_to_list(thd, $7, NULL, 0))
YYABORT;
@@ -3169,9 +3170,21 @@ create_table_option:
| CHECKSUM_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; }
| DELAY_KEY_WRITE_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; Lex->create_info.used_fields|= HA_CREATE_USED_DELAY_KEY_WRITE; }
| ROW_FORMAT_SYM opt_equal row_types { Lex->create_info.row_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_ROW_FORMAT; }
- | RAID_TYPE opt_equal raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKS opt_equal ulong_num { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKSIZE opt_equal ulong_num { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_TYPE opt_equal raid_types
+ {
+ my_error(ER_WARN_DEPRECATED_SYNTAX, MYF(0), "RAID_TYPE", "PARTITION");
+ YYABORT;
+ }
+ | RAID_CHUNKS opt_equal ulong_num
+ {
+ my_error(ER_WARN_DEPRECATED_SYNTAX, MYF(0), "RAID_CHUNKS", "PARTITION");
+ YYABORT;
+ }
+ | RAID_CHUNKSIZE opt_equal ulong_num
+ {
+ my_error(ER_WARN_DEPRECATED_SYNTAX, MYF(0), "RAID_CHUNKSIZE", "PARTITION");
+ YYABORT;
+ }
| UNION_SYM opt_equal '(' table_list ')'
{
/* Move the union list to the merge_list */
@@ -3469,7 +3482,9 @@ type:
spatial_type:
GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
| GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
- | POINT_SYM { $$= Field::GEOM_POINT; }
+ | POINT_SYM { Lex->length= (char*)"21";
+ $$= Field::GEOM_POINT;
+ }
| MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
| LINESTRING { $$= Field::GEOM_LINESTRING; }
| MULTILINESTRING { $$= Field::GEOM_MULTILINESTRING; }
@@ -3925,6 +3940,7 @@ alter:
THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
+ lex->create_view_start= thd->query;
lex->create_view_mode= VIEW_ALTER;
/* first table in list is target VIEW name */
lex->select_lex.add_table_to_list(thd, $6, NULL, 0);
@@ -4905,9 +4921,9 @@ predicate:
{ $$= new Item_func_eq(new Item_func_soundex($1),
new Item_func_soundex($4)); }
| bit_expr LIKE simple_expr opt_escape
- { $$= new Item_func_like($1,$3,$4); }
+ { $$= new Item_func_like($1,$3,$4,Lex->escape_used); }
| bit_expr not LIKE simple_expr opt_escape
- { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
+ { $$= new Item_func_not(new Item_func_like($1,$4,$5, Lex->escape_used)); }
| bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); }
| bit_expr not REGEXP bit_expr
{ $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); }
@@ -5127,6 +5143,8 @@ simple_expr:
{ $$= new Item_func_atan($3,$5); }
| CHAR_SYM '(' expr_list ')'
{ $$= new Item_func_char(*$3); }
+ | CHAR_SYM '(' expr_list USING charset_name ')'
+ { $$= new Item_func_char(*$3, $5); }
| CHARSET '(' expr ')'
{ $$= new Item_func_charset($3); }
| COALESCE '(' expr_list ')'
@@ -5814,14 +5832,22 @@ derived_table_list:
}
;
+/*
+ Notice that JOIN is a left-associative operation, and it must be parsed
+ as such, that is, the parser must process first the left join operand
+ then the right one. Such order of processing ensures that the parser
+ produces correct join trees which is essential for semantic analysis
+ and subsequent optimization phases.
+*/
join_table:
+/* INNER JOIN variants */
/*
- Evaluate production 'table_ref' before 'normal_join' so that
- [INNER | CROSS] JOIN is properly nested as other left-associative
- joins.
+ Use %prec to evaluate production 'table_ref' before 'normal_join'
+ so that [INNER | CROSS] JOIN is properly nested as other
+ left-associative joins.
*/
table_ref %prec TABLE_REF_PRIORITY normal_join table_ref
- { YYERROR_UNLESS($1 && ($$=$3)); }
+ { YYERROR_UNLESS($1 && ($$=$3)); }
| table_ref STRAIGHT_JOIN table_factor
{ YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; }
| table_ref normal_join table_ref
@@ -5863,6 +5889,13 @@ join_table:
}
'(' using_list ')'
{ add_join_natural($1,$3,$7); $$=$3; }
+ | table_ref NATURAL JOIN_SYM table_factor
+ {
+ YYERROR_UNLESS($1 && ($$=$4));
+ add_join_natural($1,$4,NULL);
+ }
+
+/* LEFT JOIN variants */
| table_ref LEFT opt_outer JOIN_SYM table_ref
ON
{
@@ -5894,6 +5927,8 @@ join_table:
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
}
+
+/* RIGHT JOIN variants */
| table_ref RIGHT opt_outer JOIN_SYM table_ref
ON
{
@@ -5931,10 +5966,7 @@ join_table:
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
- }
- | table_ref NATURAL JOIN_SYM table_factor
- { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4,NULL); };
-
+ };
normal_join:
JOIN_SYM {}
@@ -6267,10 +6299,14 @@ having_clause:
;
opt_escape:
- ESCAPE_SYM simple_expr { $$= $2; }
+ ESCAPE_SYM simple_expr
+ {
+ Lex->escape_used= TRUE;
+ $$= $2;
+ }
| /* empty */
{
-
+ Lex->escape_used= FALSE;
$$= ((YYTHD->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
new Item_string("", 0, &my_charset_latin1) :
new Item_string("\\", 1, &my_charset_latin1));
@@ -8594,6 +8630,18 @@ option_value:
$2= $2 ? $2: global_system_variables.character_set_client;
lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2));
}
+ | NAMES_SYM equal expr
+ {
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+ LEX_STRING names;
+
+ names.str= (char *)"names";
+ names.length= 5;
+ if (spc && spc->find_pvar(&names))
+ my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
+ YYABORT;
+ }
| NAMES_SYM charset_name_or_default opt_collate
{
LEX *lex= Lex;
@@ -8611,6 +8659,17 @@ option_value:
{
THD *thd=YYTHD;
LEX_USER *user;
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+ LEX_STRING pw;
+
+ pw.str= (char *)"password";
+ pw.length= 8;
+ if (spc && spc->find_pvar(&pw))
+ {
+ my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
+ YYABORT;
+ }
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
YYABORT;
user->host=null_lex_str;
@@ -9569,8 +9628,7 @@ view_user:
(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
view_user->user = $3; view_user->host=$5;
- if (strchr(view_user->host.str, wild_many) ||
- strchr(view_user->host.str, wild_one))
+ if (view_user->host.length == 0)
{
my_error(ER_NO_VIEW_USER, MYF(0));
YYABORT;
diff --git a/sql/structs.h b/sql/structs.h
index e490a2de60c..3c651c491d3 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -20,7 +20,7 @@
struct st_table;
class Field;
-#define STRING_WITH_LEN(X) X, (sizeof(X)-1)
+#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1)
typedef struct st_lex_string
{
@@ -185,6 +185,7 @@ enum SHOW_TYPE
SHOW_SSL_CTX_SESS_TIMEOUTS, SHOW_SSL_CTX_SESS_CACHE_FULL,
SHOW_SSL_GET_CIPHER_LIST,
#endif /* HAVE_OPENSSL */
+ SHOW_NET_COMPRESSION,
SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS,
SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG, SHOW_KEY_CACHE_LONGLONG,
SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS, SHOW_SLAVE_SKIP_ERRORS
diff --git a/sql/table.cc b/sql/table.cc
index d3f7d2b3b9f..776dcdf66fe 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -303,6 +303,44 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
}
#endif
+ record_offset= (ulong) (uint2korr(head+6)+
+ ((uint2korr(head+14) == 0xffff ?
+ uint4korr(head+47) : uint2korr(head+14))));
+
+ if ((n_length= uint2korr(head+55)))
+ {
+ /* Read extra data segment */
+ char *buff, *next_chunk, *buff_end;
+ if (!(next_chunk= buff= my_malloc(n_length, MYF(MY_WME))))
+ goto err;
+ buff_end= buff + n_length;
+ if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
+ MYF(MY_NABP)))
+ {
+ my_free(buff, MYF(0));
+ goto err;
+ }
+ share->connect_string.length= uint2korr(buff);
+ if (! (share->connect_string.str= strmake_root(&outparam->mem_root,
+ next_chunk + 2, share->connect_string.length)))
+ {
+ my_free(buff, MYF(0));
+ goto err;
+ }
+ next_chunk+= share->connect_string.length + 2;
+ if (next_chunk + 2 < buff_end)
+ {
+ uint str_db_type_length= uint2korr(next_chunk);
+ share->db_type= ha_resolve_by_name(next_chunk + 2, str_db_type_length);
+ DBUG_PRINT("enter", ("Setting dbtype to: %d - %d - '%.*s'\n",
+ share->db_type,
+ str_db_type_length, str_db_type_length,
+ next_chunk + 2));
+ next_chunk+= str_db_type_length + 2;
+ }
+ my_free(buff, MYF(0));
+ }
+
error=4;
outparam->reginfo.lock_type= TL_UNLOCK;
outparam->current_lock=F_UNLCK;
@@ -322,9 +360,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
goto err; /* purecov: inspected */
share->default_values= (byte *) record;
- record_offset= (ulong) (uint2korr(head+6)+
- ((uint2korr(head+14) == 0xffff ?
- uint4korr(head+47) : uint2korr(head+14))));
if (my_pread(file,(byte*) record, (uint) share->reclength,
record_offset, MYF(MY_NABP)))
goto err; /* purecov: inspected */
@@ -342,20 +377,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
else
outparam->record[1]= outparam->record[0]; // Safety
}
-
- if ((n_length= uint2korr(head+55)))
- {
- /* Read extra block information */
- char *buff;
- if (!(buff= alloc_root(&outparam->mem_root, n_length)))
- goto err;
- if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
- MYF(MY_NABP)))
- goto err;
- share->connect_string.length= uint2korr(buff);
- share->connect_string.str= buff+2;
- }
-
+
#ifdef HAVE_purify
/*
We need this because when we read var-length rows, we are not updating
@@ -463,7 +485,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
file= -1;
/* Allocate handler */
- if (!(outparam->file= get_new_handler(outparam, share->db_type)))
+ if (!(outparam->file= get_new_handler(outparam, &outparam->mem_root,
+ share->db_type)))
goto err;
record= (char*) outparam->record[0]-1; /* Fieldstart = 1 */
@@ -471,9 +494,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{
outparam->null_flags=null_pos=(uchar*) record+1;
null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;
- /* null_bytes below is only correct under the condition that
- there are no bit fields. Correct values is set below after the
- table struct is initialized */
+ /*
+ null_bytes below is only correct under the condition that
+ there are no bit fields. Correct values is set below after the
+ table struct is initialized
+ */
share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;
}
else
@@ -897,8 +922,12 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
#endif
goto err;
- /* the correct null_bytes can now be set, since bitfields have been taken into account */
- share->null_bytes= null_pos - (uchar*) outparam->null_flags + (null_bit_pos + 7) / 8;
+ /*
+ the correct null_bytes can now be set, since bitfields have been taken
+ into account
+ */
+ share->null_bytes= (null_pos - (uchar*) outparam->null_flags +
+ (null_bit_pos + 7) / 8);
share->last_null_bit_pos= null_bit_pos;
/* The table struct is now initialized; Open the table */
@@ -1410,15 +1439,10 @@ File create_frm(THD *thd, my_string name, const char *db,
ulong length;
char fill[IO_SIZE];
int create_flags= O_RDWR | O_TRUNC;
- uint extra_size;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= O_EXCL | O_NOFOLLOW;
- extra_size= 0;
- if (create_info->connect_string.length)
- extra_size= 2+create_info->connect_string.length;
-
#if SIZEOF_OFF_T > 4
/* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */
if (create_info->max_rows > ~(ulong) 0)
@@ -1446,7 +1470,8 @@ File create_frm(THD *thd, my_string name, const char *db,
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
- length= next_io_size((ulong) (IO_SIZE+key_length+reclength+extra_size));
+ length= next_io_size((ulong) (IO_SIZE+key_length+reclength+
+ create_info->extra_size));
int4store(fileinfo+10,length);
tmp_key_length= (key_length < 0xffff) ? key_length : 0xffff;
int2store(fileinfo+14,tmp_key_length);
@@ -1468,7 +1493,7 @@ File create_frm(THD *thd, my_string name, const char *db,
int4store(fileinfo+47, key_length);
tmp= MYSQL_VERSION_ID; // Store to avoid warning from int4store
int4store(fileinfo+51, tmp);
- int2store(fileinfo+55, extra_size);
+ int2store(fileinfo+55, create_info->extra_size);
bzero(fill,IO_SIZE);
for (; length > IO_SIZE ; length-= IO_SIZE)
{
@@ -1709,29 +1734,6 @@ bool check_column_name(const char *name)
}
/*
-** Get type of table from .frm file
-*/
-
-db_type get_table_type(THD *thd, const char *name)
-{
- File file;
- uchar head[4];
- int error;
- DBUG_ENTER("get_table_type");
- DBUG_PRINT("enter",("name: '%s'",name));
-
- if ((file=my_open(name,O_RDONLY, MYF(0))) < 0)
- DBUG_RETURN(DB_TYPE_UNKNOWN);
- error=my_read(file,(byte*) head,4,MYF(MY_NABP));
- my_close(file,MYF(0));
- if (error || head[0] != (uchar) 254 || head[1] != 1 ||
- (head[2] != FRM_VER && head[2] != FRM_VER+1 &&
- (head[2] < FRM_VER+3 || head[2] > FRM_VER+4)))
- DBUG_RETURN(DB_TYPE_UNKNOWN);
- DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0));
-}
-
-/*
Create Item_field for each column in the table.
SYNPOSIS
@@ -1814,41 +1816,43 @@ void st_table_list::calc_md5(char *buffer)
/*
- set ancestor TABLE for table place holder of VIEW
+ set underlying TABLE for table place holder of VIEW
DESCRIPTION
Replace all views that only uses one table with the table itself.
This allows us to treat the view as a simple table and even update
- it
+ it (it is a kind of optimisation)
SYNOPSIS
- st_table_list::set_ancestor()
+ st_table_list::set_underlying_merge()
*/
-void st_table_list::set_ancestor()
+void st_table_list::set_underlying_merge()
{
TABLE_LIST *tbl;
- if ((tbl= ancestor))
+ if ((tbl= merge_underlying_list))
{
/* This is a view. Process all tables of view */
- DBUG_ASSERT(view);
+ DBUG_ASSERT(view && effective_algorithm == VIEW_ALGORITHM_MERGE);
do
{
- if (tbl->ancestor) // This is a view
+ if (tbl->merge_underlying_list) // This is a view
{
+ DBUG_ASSERT(tbl->view &&
+ tbl->effective_algorithm == VIEW_ALGORITHM_MERGE);
/*
This is the only case where set_ancestor is called on an object
that may not be a view (in which case ancestor is 0)
*/
- tbl->ancestor->set_ancestor();
+ tbl->merge_underlying_list->set_underlying_merge();
}
} while ((tbl= tbl->next_local));
if (!multitable_view)
{
- table= ancestor->table;
- schema_table= ancestor->schema_table;
+ table= merge_underlying_list->table;
+ schema_table= merge_underlying_list->schema_table;
}
}
}
@@ -1858,12 +1862,9 @@ void st_table_list::set_ancestor()
setup fields of placeholder of merged VIEW
SYNOPSIS
- st_table_list::setup_ancestor()
+ st_table_list::setup_underlying()
thd - thread handler
- NOTES
- ancestor is list of tables and views used by view (underlying tables/views)
-
DESCRIPTION
It is:
- preparing translation table for view columns
@@ -1874,10 +1875,11 @@ void st_table_list::set_ancestor()
TRUE - error
*/
-bool st_table_list::setup_ancestor(THD *thd)
+bool st_table_list::setup_underlying(THD *thd)
{
- DBUG_ENTER("st_table_list::setup_ancestor");
- if (!field_translation)
+ DBUG_ENTER("st_table_list::setup_underlying");
+
+ if (!field_translation && merge_underlying_list)
{
Field_translator *transl;
SELECT_LEX *select= &view->select_lex;
@@ -1891,10 +1893,10 @@ bool st_table_list::setup_ancestor(THD *thd)
DBUG_RETURN(TRUE);
}
- for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ for (tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
- if (tbl->ancestor &&
- tbl->setup_ancestor(thd))
+ if (tbl->merge_underlying_list &&
+ tbl->setup_underlying(thd))
{
DBUG_RETURN(TRUE);
}
@@ -1957,7 +1959,7 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
{
DBUG_ENTER("st_table_list::prep_where");
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
if (tbl->view && tbl->prep_where(thd, conds, no_where_clause))
{
@@ -2039,7 +2041,7 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
{
DBUG_ENTER("st_table_list::prep_check_option");
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
/* see comment of check_opt_type parameter */
if (tbl->view &&
@@ -2062,7 +2064,7 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
}
if (check_opt_type == VIEW_CHECK_CASCADED)
{
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
if (tbl->check_option)
item= and_conds(item, tbl->check_option);
@@ -2101,16 +2103,21 @@ void st_table_list::hide_view_error(THD *thd)
{
/* Hide "Unknown column" or "Unknown function" error */
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
- thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
+ thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
+ thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
+ thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR)
{
+ TABLE_LIST *top= top_table();
thd->clear_error();
- my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
+ my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
}
else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
{
+ TABLE_LIST *top= top_table();
thd->clear_error();
// TODO: make correct error message
- my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str);
+ my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0),
+ top->view_db.str, top->view_name.str);
}
}
@@ -2131,10 +2138,10 @@ void st_table_list::hide_view_error(THD *thd)
st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
{
/* is this real table and table which we are looking for? */
- if (table == table_to_find && ancestor == 0)
+ if (table == table_to_find && merge_underlying_list == 0)
return this;
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
TABLE_LIST *result;
if ((result= tbl->find_underlying_table(table_to_find)))
@@ -2217,7 +2224,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
bool st_table_list::check_single_table(st_table_list **table, table_map map,
st_table_list *view)
{
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
if (tbl->table)
{
@@ -2259,8 +2266,8 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
}
else
{
- DBUG_ASSERT(view && ancestor);
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ DBUG_ASSERT(view && merge_underlying_list);
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
if (tbl->set_insert_values(mem_root))
return TRUE;
}
@@ -2406,6 +2413,157 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
}
+/*
+ Register access mode which we need for underlying tables
+
+ SYNOPSIS
+ register_want_access()
+ want_access Acess which we require
+*/
+
+void st_table_list::register_want_access(ulong want_access)
+{
+ /* Remove SHOW_VIEW_ACL, because it will be checked during making view */
+ want_access&= ~SHOW_VIEW_ACL;
+ if (belong_to_view)
+ {
+ grant.want_privilege= want_access;
+ if (table)
+ table->grant.want_privilege= want_access;
+ }
+ for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
+ tbl->register_want_access(want_access);
+}
+
+
+/*
+ Load security context information for this view
+
+ SYNOPSIS
+ st_table_list::prepare_view_securety_context()
+ thd [in] thread handler
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+bool st_table_list::prepare_view_securety_context(THD *thd)
+{
+ DBUG_ENTER("st_table_list::prepare_view_securety_context");
+ DBUG_PRINT("enter", ("table: %s", alias));
+
+ DBUG_ASSERT(!prelocking_placeholder && view);
+ if (view_suid)
+ {
+ DBUG_PRINT("info", ("This table is suid view => load contest"));
+ DBUG_ASSERT(view && view_sctx);
+ if (acl_getroot_no_password(view_sctx,
+ definer.user.str,
+ definer.host.str,
+ definer.host.str,
+ thd->db))
+ {
+ my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+#endif
+
+
+/*
+ Find security context of current view
+
+ SYNOPSIS
+ st_table_list::find_view_security_context()
+ thd [in] thread handler
+
+*/
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+Security_context *st_table_list::find_view_security_context(THD *thd)
+{
+ Security_context *sctx;
+ TABLE_LIST *upper_view= this;
+ DBUG_ENTER("st_table_list::find_view_security_context");
+
+ DBUG_ASSERT(view);
+ while (upper_view && !upper_view->view_suid)
+ {
+ DBUG_ASSERT(!upper_view->prelocking_placeholder);
+ upper_view= upper_view->referencing_view;
+ }
+ if (upper_view)
+ {
+ DBUG_PRINT("info", ("Securety context of view %s will be used",
+ upper_view->alias));
+ sctx= upper_view->view_sctx;
+ DBUG_ASSERT(sctx);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Current global context will be used"));
+ sctx= thd->security_ctx;
+ }
+ DBUG_RETURN(sctx);
+}
+#endif
+
+
+/*
+ Prepare security context and load underlying tables priveleges for view
+
+ SYNOPSIS
+ st_table_list::prepare_security()
+ thd [in] thread handler
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool st_table_list::prepare_security(THD *thd)
+{
+ List_iterator_fast<TABLE_LIST> tb(*view_tables);
+ TABLE_LIST *tbl;
+ DBUG_ENTER("st_table_list::prepare_security");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_security_ctx= thd->security_ctx;
+
+ DBUG_ASSERT(!prelocking_placeholder);
+ if (prepare_view_securety_context(thd))
+ DBUG_RETURN(TRUE);
+ thd->security_ctx= find_view_security_context(thd);
+ while ((tbl= tb++))
+ {
+ DBUG_ASSERT(tbl->referencing_view);
+ char *db, *table_name;
+ if (tbl->view)
+ {
+ db= tbl->view_db.str;
+ table_name= tbl->view_name.str;
+ }
+ else
+ {
+ db= tbl->db;
+ table_name= tbl->table_name;
+ }
+ fill_effective_table_privileges(thd, &tbl->grant, db, table_name);
+ if (tbl->table)
+ tbl->table->grant= grant;
+ }
+ thd->security_ctx= save_security_ctx;
+#else
+ while ((tbl= tb++))
+ tbl->grant.privilege= ~NO_ACCESS;
+#endif
+ DBUG_RETURN(FALSE);
+}
+
+
Natural_join_column::Natural_join_column(Field_translator *field_param,
TABLE_LIST *tab)
{
@@ -2514,6 +2672,9 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
GRANT_INFO *grant;
const char *db_name;
const char *table_name;
+ Security_context *save_security_ctx= thd->security_ctx;
+ Security_context *new_sctx= table_ref->security_ctx;
+ bool res;
if (view_field)
{
@@ -2530,7 +2691,11 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
table_name= table_ref->table->s->table_name;
}
- return check_grant_column(thd, grant, db_name, table_name, name, length);
+ if (new_sctx)
+ thd->security_ctx= new_sctx;
+ res= check_grant_column(thd, grant, db_name, table_name, name, length);
+ thd->security_ctx= save_security_ctx;
+ return res;
}
#endif
diff --git a/sql/table.h b/sql/table.h
index c1de61ef273..40c01a1c051 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -23,6 +23,7 @@ class st_select_lex_unit;
class st_select_lex;
class partition_info;
class COND_EQUAL;
+class Security_context;
/* Order clause list element */
@@ -48,6 +49,11 @@ typedef struct st_grant_info
uint version;
ulong privilege;
ulong want_privilege;
+ /*
+ Stores the requested access acl of top level tables list. Is used to
+ check access rights to the underlying tables of a view.
+ */
+ ulong orig_want_privilege;
} GRANT_INFO;
enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2,
@@ -366,7 +372,6 @@ typedef struct st_schema_table
#define VIEW_CHECK_SKIP 2
struct st_lex;
-struct st_table_list;
class select_union;
class TMP_TABLE_PARAM;
@@ -532,11 +537,36 @@ typedef struct st_table_list
Field_translator *field_translation; /* array of VIEW fields */
/* pointer to element after last one in translation table above */
Field_translator *field_translation_end;
- /* list of ancestor(s) of this table (underlying table(s)/view(s) */
- st_table_list *ancestor;
+ /*
+ List (based on next_local) of underlying tables of this view. I.e. it
+ does not include the tables of subqueries used in the view. Is set only
+ for merged views.
+ */
+ st_table_list *merge_underlying_list;
+ /*
+ - 0 for base tables
+ - in case of the view it is the list of all (not only underlying
+ tables but also used in subquery ones) tables of the view.
+ */
+ List<st_table_list> *view_tables;
/* most upper view this table belongs to */
st_table_list *belong_to_view;
/*
+ The view directly referencing this table
+ (non-zero only for merged underlying tables of a view).
+ */
+ st_table_list *referencing_view;
+ /*
+ Security context (non-zero only for tables which belong
+ to view with SQL SECURITY DEFINER)
+ */
+ Security_context *security_ctx;
+ /*
+ This view security context (non-zero only for views with
+ SQL SECURITY DEFINER)
+ */
+ Security_context *view_sctx;
+ /*
List of all base tables local to a subquery including all view
tables. Unlike 'next_local', this in this list views are *not*
leaves. Created in setup_tables() -> make_leaves_list().
@@ -592,8 +622,6 @@ typedef struct st_table_list
bool compact_view_format; /* Use compact format for SHOW CREATE VIEW */
/* view where processed */
bool where_processed;
- /* db part was not defined in table definition */
- bool current_db_used;
/* FRMTYPE_ERROR if any type is acceptable */
enum frm_type_enum required_type;
char timestamp_buffer[20]; /* buffer for timestamp (19+1) */
@@ -604,9 +632,9 @@ typedef struct st_table_list
bool prelocking_placeholder;
void calc_md5(char *buffer);
- void set_ancestor();
+ void set_underlying_merge();
int view_check_option(THD *thd, bool ignore_failure);
- bool setup_ancestor(THD *thd);
+ bool setup_underlying(THD *thd);
void cleanup_items();
bool placeholder() {return derived || view; }
void print(THD *thd, String *str);
@@ -634,6 +662,14 @@ typedef struct st_table_list
return prep_where(thd, conds, no_where_clause);
return FALSE;
}
+
+ void register_want_access(ulong want_access);
+ bool prepare_security(THD *thd);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *find_view_security_context(THD *thd);
+ bool prepare_view_securety_context(THD *thd);
+#endif
+
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 592093350f1..86f4b49292a 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -76,6 +76,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
uint keys, KEY *key_info,
handler *db_file)
{
+ LEX_STRING str_db_type;
uint reclength,info_length,screens,key_info_length,maxlength;
ulong key_buff_length;
File file;
@@ -83,6 +84,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
+ char buff[2];
#ifdef HAVE_PARTITION_DB
partition_info *part_info= thd->lex->part_info;
#endif
@@ -122,6 +124,12 @@ bool mysql_create_frm(THD *thd, my_string file_name,
}
reclength=uint2korr(forminfo+266);
+ /* Calculate extra data segment length */
+ str_db_type.str= (char *) ha_get_storage_engine(create_info->db_type);
+ str_db_type.length= strlen(str_db_type.str);
+ create_info->extra_size= (2 + str_db_type.length +
+ 2 + create_info->connect_string.length);
+
if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
create_info, keys)) < 0)
{
@@ -163,16 +171,19 @@ bool mysql_create_frm(THD *thd, my_string file_name,
if (make_empty_rec(thd,file,create_info->db_type,create_info->table_options,
create_fields,reclength, data_offset, db_file))
goto err;
- if (create_info->connect_string.length)
- {
- char buff[2];
- int2store(buff,create_info->connect_string.length);
- if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
- my_write(file, (const byte*)create_info->connect_string.str,
- create_info->connect_string.length, MYF(MY_NABP)))
+
+ int2store(buff, create_info->connect_string.length);
+ if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
+ my_write(file, (const byte*)create_info->connect_string.str,
+ create_info->connect_string.length, MYF(MY_NABP)))
goto err;
- }
+ int2store(buff, str_db_type.length);
+ if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
+ my_write(file, (const byte*)str_db_type.str,
+ str_db_type.length, MYF(MY_NABP)))
+ goto err;
+
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||
@@ -497,16 +508,10 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
char *dst;
uint length= field->interval->type_lengths[pos], hex_length;
const char *src= field->interval->type_names[pos];
- const char *srcend= src + length;
hex_length= length * 2;
field->interval->type_lengths[pos]= hex_length;
field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
- for ( ; src < srcend; src++)
- {
- *dst++= _dig_vec_upper[((uchar) *src) >> 4];
- *dst++= _dig_vec_upper[((uchar) *src) & 15];
- }
- *dst= '\0';
+ octet2hex(dst, src, length);
}
}