diff options
author | unknown <igor@rurik.mysql.com> | 2005-11-22 23:00:57 -0800 |
---|---|---|
committer | unknown <igor@rurik.mysql.com> | 2005-11-22 23:00:57 -0800 |
commit | c3c232a88cc911ccd6b59b80ec93cc8b3de51001 (patch) | |
tree | f8ae80abeb1f01b0ecf98787da39162a6013417a /sql | |
parent | 806482c7e45aceac81fe3999197d3a3724653c03 (diff) | |
parent | 4aea839bde48c615d2d672ebbd29f20c297fe670 (diff) | |
download | mariadb-git-c3c232a88cc911ccd6b59b80ec93cc8b3de51001.tar.gz |
Merge rurik.mysql.com:/home/igor/mysql-5.0
into rurik.mysql.com:/home/igor/dev/mysql-5.0-2
mysql-test/r/func_gconcat.result:
Auto merged
mysql-test/t/func_gconcat.test:
Auto merged
sql/item.cc:
Auto merged
sql/item.h:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_strfunc.cc:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/item_sum.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_prepare.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
Diffstat (limited to 'sql')
63 files changed, 1585 insertions, 834 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index 2450f18c970..1437751bf2f 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -122,17 +122,17 @@ AM_YFLAGS = -d mysql_tzinfo_to_sql.cc: rm -f mysql_tzinfo_to_sql.cc - @LN_CP_F@ tztime.cc mysql_tzinfo_to_sql.cc + @LN_CP_F@ $(srcdir)/tztime.cc mysql_tzinfo_to_sql.cc link_sources: mysql_tzinfo_to_sql.cc rm -f mini_client_errors.c - @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c + @LN_CP_F@ $(top_srcdir)/libmysql/errmsg.c mini_client_errors.c rm -f pack.c - @LN_CP_F@ ../sql-common/pack.c pack.c + @LN_CP_F@ $(top_srcdir)/sql-common/pack.c pack.c rm -f client.c - @LN_CP_F@ ../sql-common/client.c client.c + @LN_CP_F@ $(top_srcdir)/sql-common/client.c client.c rm -f my_time.c - @LN_CP_F@ ../sql-common/my_time.c my_time.c + @LN_CP_F@ $(top_srcdir)/sql-common/my_time.c my_time.c mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES) $(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $< diff --git a/sql/field.cc b/sql/field.cc index 381a13c3263..b70e2a92618 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1272,9 +1272,9 @@ my_decimal *Field::val_decimal(my_decimal *decimal) void Field_num::add_zerofill_and_unsigned(String &res) const { if (unsigned_flag) - res.append(" unsigned"); + res.append(STRING_WITH_LEN(" unsigned")); if (zerofill) - res.append(" zerofill"); + res.append(STRING_WITH_LEN(" zerofill")); } @@ -1655,7 +1655,7 @@ bool Field::needs_quotes(void) void Field_null::sql_type(String &res) const { - res.set_ascii("null", 4); + res.set_ascii(STRING_WITH_LEN("null")); } @@ -1667,7 +1667,7 @@ void Field_null::sql_type(String &res) const void Field_decimal::reset(void) { - Field_decimal::store("0",1,&my_charset_bin); + Field_decimal::store(STRING_WITH_LEN("0"),&my_charset_bin); } void Field_decimal::overflow(bool negative) @@ -4113,7 +4113,7 @@ void Field_float::sql_type(String &res) const { if (dec == NOT_FIXED_DEC) { - res.set_ascii("float", 5); + res.set_ascii(STRING_WITH_LEN("float")); } else { @@ -4384,7 +4384,7 @@ void Field_double::sql_type(String &res) const CHARSET_INFO *cs=res.charset(); if (dec == NOT_FIXED_DEC) { - res.set_ascii("double",6); + res.set_ascii(STRING_WITH_LEN("double")); } else { @@ -4673,7 +4673,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) if (temp == 0L) { /* Zero time is "000000" */ - val_ptr->set("0000-00-00 00:00:00", 19, &my_charset_bin); + val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin); return val_ptr; } val_buffer->set_charset(&my_charset_bin); // Safety @@ -4805,7 +4805,7 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - res.set_ascii("timestamp", 9); + res.set_ascii(STRING_WITH_LEN("timestamp")); } @@ -5074,7 +5074,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused))) void Field_time::sql_type(String &res) const { - res.set_ascii("time", 4); + res.set_ascii(STRING_WITH_LEN("time")); } /**************************************************************************** @@ -5381,7 +5381,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused))) void Field_date::sql_type(String &res) const { - res.set_ascii("date", 4); + res.set_ascii(STRING_WITH_LEN("date")); } @@ -5564,7 +5564,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) void Field_newdate::sql_type(String &res) const { - res.set_ascii("date", 4); + res.set_ascii(STRING_WITH_LEN("date")); } @@ -5838,7 +5838,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused))) void Field_datetime::sql_type(String &res) const { - res.set_ascii("datetime", 8); + res.set_ascii(STRING_WITH_LEN("datetime")); } /**************************************************************************** @@ -6061,7 +6061,7 @@ void Field_string::sql_type(String &res) const res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) - res.append(" binary"); + res.append(STRING_WITH_LEN(" binary")); } @@ -6194,6 +6194,8 @@ uint Field_string::max_packed_col_length(uint max_length) Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) { + Field *new_field; + if (type() != MYSQL_TYPE_VAR_STRING || table == new_table) return Field::new_field(root, new_table); @@ -6202,15 +6204,16 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) This is done to ensure that ALTER TABLE will convert old VARCHAR fields to now VARCHAR fields. */ - Field *new_field= new Field_varstring(field_length, maybe_null(), - field_name, new_table, - charset()); - /* - delayed_insert::get_local_table() needs a ptr copied from old table. - This is what other new_field() methods do too. The above method of - Field_varstring sets ptr to NULL. - */ - new_field->ptr= ptr; + if (new_field= new Field_varstring(field_length, maybe_null(), + field_name, new_table, charset())) + { + /* + delayed_insert::get_local_table() needs a ptr copied from old table. + This is what other new_field() methods do too. The above method of + Field_varstring sets ptr to NULL. + */ + new_field->ptr= ptr; + } return new_field; } @@ -6454,7 +6457,7 @@ void Field_varstring::sql_type(String &res) const res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) - res.append(" binary"); + res.append(STRING_WITH_LEN(" binary")); } @@ -7174,10 +7177,10 @@ void Field_blob::sql_type(String &res) const } res.set_ascii(str,length); if (charset() == &my_charset_bin) - res.append("blob"); + res.append(STRING_WITH_LEN("blob")); else { - res.append("text"); + res.append(STRING_WITH_LEN("text")); } } @@ -7397,28 +7400,28 @@ void Field_geom::sql_type(String &res) const switch (geom_type) { case GEOM_POINT: - res.set("point", 5, cs); + res.set(STRING_WITH_LEN("point"), cs); break; case GEOM_LINESTRING: - res.set("linestring", 10, cs); + res.set(STRING_WITH_LEN("linestring"), cs); break; case GEOM_POLYGON: - res.set("polygon", 7, cs); + res.set(STRING_WITH_LEN("polygon"), cs); break; case GEOM_MULTIPOINT: - res.set("multipoint", 10, cs); + res.set(STRING_WITH_LEN("multipoint"), cs); break; case GEOM_MULTILINESTRING: - res.set("multilinestring", 15, cs); + res.set(STRING_WITH_LEN("multilinestring"), cs); break; case GEOM_MULTIPOLYGON: - res.set("multipolygon", 12, cs); + res.set(STRING_WITH_LEN("multipolygon"), cs); break; case GEOM_GEOMETRYCOLLECTION: - res.set("geometrycollection", 18, cs); + res.set(STRING_WITH_LEN("geometrycollection"), cs); break; default: - res.set("geometry", 8, cs); + res.set(STRING_WITH_LEN("geometry"), cs); } } @@ -7695,7 +7698,7 @@ void Field_enum::sql_type(String &res) const String enum_item(buffer, sizeof(buffer), res.charset()); res.length(0); - res.append("enum("); + res.append(STRING_WITH_LEN("enum(")); bool flag=0; uint *len= typelib->type_lengths; @@ -7809,7 +7812,7 @@ void Field_set::sql_type(String &res) const String set_item(buffer, sizeof(buffer), res.charset()); res.length(0); - res.append("set("); + res.append(STRING_WITH_LEN("set(")); bool flag=0; uint *len= typelib->type_lengths; diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 3a2bdf3ef9a..72af402a0dc 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -308,7 +308,7 @@ int berkeley_show_logs(Protocol *protocol) { protocol->prepare_for_resend(); protocol->store(*a, system_charset_info); - protocol->store("BDB", 3, system_charset_info); + protocol->store(STRING_WITH_LEN("BDB"), system_charset_info); if (f && *f && strcmp(*a, *f) == 0) { f++; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index d6d6b5980f6..3ab246df012 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2615,7 +2615,7 @@ int ha_federated::stash_remote_error() { DBUG_ENTER("ha_federated::stash_remote_error()"); remote_error_number= mysql_errno(mysql); - my_snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE, + my_snprintf(remote_error_buf, sizeof(remote_error_buf), "%s", mysql_error(mysql)); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); } @@ -2627,10 +2627,10 @@ bool ha_federated::get_error_message(int error, String* buf) DBUG_PRINT("enter", ("error: %d", error)); if (error == HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM) { - buf->append("Error on remote system: "); + buf->append(STRING_WITH_LEN("Error on remote system: ")); buf->qs_append(remote_error_number); - buf->append(": "); - buf->append(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE); + buf->append(STRING_WITH_LEN(": ")); + buf->append(remote_error_buf); remote_error_number= 0; remote_error_buf[0]= '\0'; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 60ec6f8e2bb..56e5fd8923f 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2198,11 +2198,13 @@ innobase_savepoint( DBUG_ENTER("innobase_savepoint"); - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - /* In the autocommit state there is no sense to set a - savepoint: we return immediate success */ - DBUG_RETURN(0); - } + /* + In the autocommit mode there is no sense to set a savepoint + (unless we are in sub-statement), so SQL layer ensures that + this method is never called in such situation. + */ + DBUG_ASSERT(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) || + thd->in_sub_stmt); trx = check_trx_exists(thd); diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 5911d6c0fbc..da4136def68 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -490,10 +490,10 @@ void ha_myisammrg::append_create_info(String *packet) if (file->merge_insert_method != MERGE_INSERT_DISABLED) { - packet->append(" INSERT_METHOD=",15); + packet->append(STRING_WITH_LEN(" INSERT_METHOD=")); packet->append(get_type(&merge_insert_method,file->merge_insert_method-1)); } - packet->append(" UNION=(",8); + packet->append(STRING_WITH_LEN(" UNION=(")); MYRG_TABLE *open_table,*first; current_db= table->s->db; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 80c34f1117f..cdd406d473c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -78,6 +78,8 @@ handlerton ndbcluster_hton = { #define NDB_FAILED_AUTO_INCREMENT ~(Uint64)0 #define NDB_AUTO_INCREMENT_RETRIES 10 +#define NDB_INVALID_SCHEMA_OBJECT 241 + #define ERR_PRINT(err) \ DBUG_PRINT("error", ("%d message: %s", err.code, err.message)) @@ -296,7 +298,21 @@ Thd_ndb::Thd_ndb() Thd_ndb::~Thd_ndb() { if (ndb) + { +#ifndef DBUG_OFF + Ndb::Free_list_usage tmp; tmp.m_name= 0; + while (ndb->get_free_list_usage(&tmp)) + { + uint leaked= (uint) tmp.m_created - tmp.m_free; + if (leaked) + fprintf(stderr, "NDB: Found %u %s%s that %s not been released\n", + leaked, tmp.m_name, + (leaked == 1)?"":"'s", + (leaked == 1)?"has":"have"); + } +#endif delete ndb; + } ndb= NULL; changed_tables.empty(); } @@ -3316,15 +3332,18 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); } - if (m_table != (void *)tab || m_table_version < tab->getObjectVersion()) + if (m_table != (void *)tab) { - /* - The table has been altered, refresh the index list - */ - build_index_list(ndb, table, ILBP_OPEN); m_table= (void *)tab; m_table_version = tab->getObjectVersion(); } + else if (m_table_version < tab->getObjectVersion()) + { + /* + The table has been altered, caller has to retry + */ + DBUG_RETURN(my_errno= HA_ERR_TABLE_DEF_CHANGED); + } m_table_info= tab_info; } no_uncommitted_rows_init(thd); @@ -4862,7 +4881,21 @@ bool ndbcluster_end() (void) pthread_mutex_unlock(&LOCK_ndb_util_thread); if (g_ndb) + { +#ifndef DBUG_OFF + Ndb::Free_list_usage tmp; tmp.m_name= 0; + while (g_ndb->get_free_list_usage(&tmp)) + { + uint leaked= (uint) tmp.m_created - tmp.m_free; + if (leaked) + fprintf(stderr, "NDB: Found %u %s%s that %s not been released\n", + leaked, tmp.m_name, + (leaked == 1)?"":"'s", + (leaked == 1)?"has":"have"); + } +#endif delete g_ndb; + } g_ndb= NULL; if (g_ndb_cluster_connection) delete g_ndb_cluster_connection; diff --git a/sql/handler.cc b/sql/handler.cc index 7724b27949e..477a6f9bdae 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1145,10 +1145,10 @@ int ha_update_statistics() int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - THD_TRANS *trans=&thd->transaction.all; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); handlerton **ht=trans->ht, **end_ht; DBUG_ENTER("ha_rollback_to_savepoint"); - DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0); trans->nht=sv->nht; trans->no_2pc=0; @@ -1176,7 +1176,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) for (; *ht ; ht++) { int err; - if ((err= (*(*ht)->rollback)(thd, 1))) + if ((err= (*(*ht)->rollback)(thd, !thd->in_sub_stmt))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; @@ -1196,10 +1196,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) int ha_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - THD_TRANS *trans=&thd->transaction.all; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); handlerton **ht=trans->ht; DBUG_ENTER("ha_savepoint"); - DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0); #ifdef USING_TRANSACTIONS for (; *ht; ht++) { @@ -1225,9 +1225,10 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) int ha_release_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - handlerton **ht=thd->transaction.all.ht, **end_ht; + THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : + &thd->transaction.all); + handlerton **ht=trans->ht, **end_ht; DBUG_ENTER("ha_release_savepoint"); - DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0); end_ht=ht+sv->nht; for (; ht < end_ht; ht++) @@ -1684,7 +1685,7 @@ void handler::print_error(int error, myf errflag) if (str.length() >= max_length) { str.length(max_length-4); - str.append("..."); + str.append(STRING_WITH_LEN("...")); } my_error(ER_DUP_ENTRY, MYF(0), str.c_ptr(), key_nr+1); DBUG_VOID_RETURN; diff --git a/sql/item.cc b/sql/item.cc index 9def2e3defa..c1349d9da9b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -383,7 +383,7 @@ void Item::print_item_w_name(String *str) if (name) { THD *thd= current_thd; - str->append(" AS ", 4); + str->append(STRING_WITH_LEN(" AS ")); append_identifier(thd, str, name, (uint) strlen(name)); } } @@ -894,6 +894,7 @@ bool Item_splocal::is_null() Item * Item_splocal::this_item() { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset); } @@ -901,12 +902,14 @@ Item_splocal::this_item() Item ** Item_splocal::this_item_addr(THD *thd, Item **addr) { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item_addr(m_offset); } Item * Item_splocal::this_const_item() const { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset); } @@ -914,7 +917,10 @@ Item::Type Item_splocal::type() const { if (thd && thd->spcont) + { + DBUG_ASSERT(owner == thd->spcont->owner); return thd->spcont->get_item(m_offset)->type(); + } return NULL_ITEM; // Anything but SUBSELECT_ITEM } @@ -1031,7 +1037,7 @@ void Item_name_const::cleanup() void Item_name_const::print(String *str) { - str->append("NAME_CONST("); + str->append(STRING_WITH_LEN("NAME_CONST(")); name_item->print(str); str->append(','); value_item->print(str); @@ -4864,7 +4870,7 @@ void Item_ref::make_field(Send_field *field) void Item_ref_null_helper::print(String *str) { - str->append("<ref_null_helper>(", 18); + str->append(STRING_WITH_LEN("<ref_null_helper>(")); if (ref) (*ref)->print(str); else @@ -4990,7 +4996,7 @@ bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const void Item_null_helper::print(String *str) { - str->append("<null_helper>(", 14); + str->append(STRING_WITH_LEN("<null_helper>(")); store->print(str); str->append(')'); } @@ -5050,10 +5056,10 @@ void Item_default_value::print(String *str) { if (!arg) { - str->append("default", 7); + str->append(STRING_WITH_LEN("default")); return; } - str->append("default(", 8); + str->append(STRING_WITH_LEN("default(")); arg->print(str); str->append(')'); } @@ -5147,7 +5153,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) void Item_insert_value::print(String *str) { - str->append("values(", 7); + str->append(STRING_WITH_LEN("values(")); arg->print(str); str->append(')'); } @@ -5408,7 +5414,7 @@ Item_cache* Item_cache::get_cache(Item_result type) void Item_cache::print(String *str) { - str->append("<cache>(", 8); + str->append(STRING_WITH_LEN("<cache>(")); if (example) example->print(str); else diff --git a/sql/item.h b/sql/item.h index 7e6a6ea074c..8306dfa8b7a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -704,6 +704,8 @@ public: }; +class sp_head; + /* A reference to local SP variable (incl. reference to SP parameter), used in runtime. @@ -721,6 +723,13 @@ class Item_splocal : public Item uint m_offset; public: +#ifndef DBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *owner; +#endif LEX_STRING m_name; THD *thd; @@ -1055,7 +1064,7 @@ public: bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } - void print(String *str) { str->append("NULL", 4); } + void print(String *str) { str->append(STRING_WITH_LEN("NULL")); } Item *safe_charset_converter(CHARSET_INFO *tocs); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e77fb159d53..ca070131122 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1175,10 +1175,10 @@ void Item_func_between::print(String *str) str->append('('); args[0]->print(str); if (negated) - str->append(" not", 4); - str->append(" between ", 9); + str->append(STRING_WITH_LEN(" not")); + str->append(STRING_WITH_LEN(" between ")); args[1]->print(str); - str->append(" and ", 5); + str->append(STRING_WITH_LEN(" and ")); args[2]->print(str); str->append(')'); } @@ -1793,7 +1793,7 @@ uint Item_func_case::decimal_precision() const void Item_func_case::print(String *str) { - str->append("(case ", 6); + str->append(STRING_WITH_LEN("(case ")); if (first_expr_num != -1) { args[first_expr_num]->print(str); @@ -1801,19 +1801,19 @@ void Item_func_case::print(String *str) } for (uint i=0 ; i < ncases ; i+=2) { - str->append("when ", 5); + str->append(STRING_WITH_LEN("when ")); args[i]->print(str); - str->append(" then ", 6); + str->append(STRING_WITH_LEN(" then ")); args[i+1]->print(str); str->append(' '); } if (else_expr_num != -1) { - str->append("else ", 5); + str->append(STRING_WITH_LEN("else ")); args[else_expr_num]->print(str); str->append(' '); } - str->append("end)", 4); + str->append(STRING_WITH_LEN("end)")); } /* @@ -2419,10 +2419,10 @@ void Item_func_in::print(String *str) str->append('('); args[0]->print(str); if (negated) - str->append(" not", 4); - str->append(" in (", 5); + str->append(STRING_WITH_LEN(" not")); + str->append(STRING_WITH_LEN(" in (")); print_args(str, 1); - str->append("))", 2); + str->append(STRING_WITH_LEN("))")); } @@ -2894,7 +2894,7 @@ void Item_func_isnotnull::print(String *str) { str->append('('); args[0]->print(str); - str->append(" is not null)", 13); + str->append(STRING_WITH_LEN(" is not null)")); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 7b46dd964c1..f35265f9135 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -794,9 +794,9 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) void Item_func_signed::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as signed)", 11); + str->append(STRING_WITH_LEN(" as signed)")); } @@ -855,9 +855,9 @@ longlong Item_func_signed::val_int() void Item_func_unsigned::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as unsigned)", 13); + str->append(STRING_WITH_LEN(" as unsigned)")); } @@ -927,9 +927,9 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) void Item_decimal_typecast::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as decimal)", 12); + str->append(STRING_WITH_LEN(" as decimal)")); } @@ -2234,7 +2234,7 @@ longlong Item_func_locate::val_int() void Item_func_locate::print(String *str) { - str->append("locate(", 7); + str->append(STRING_WITH_LEN("locate(")); args[1]->print(str); str->append(','); args[0]->print(str); @@ -3297,7 +3297,7 @@ longlong Item_func_benchmark::val_int() void Item_func_benchmark::print(String *str) { - str->append("benchmark(", 10); + str->append(STRING_WITH_LEN("benchmark(")); char buffer[20]; // my_charset_bin is good enough for numbers String st(buffer, sizeof(buffer), &my_charset_bin); @@ -3811,9 +3811,9 @@ my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) void Item_func_set_user_var::print(String *str) { - str->append("(@", 2); + str->append(STRING_WITH_LEN("(@")); str->append(name.str, name.length); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); args[0]->print(str); str->append(')'); } @@ -3821,9 +3821,9 @@ void Item_func_set_user_var::print(String *str) void Item_func_set_user_var::print_as_stmt(String *str) { - str->append("set @", 5); + str->append(STRING_WITH_LEN("set @")); str->append(name.str, name.length); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); args[0]->print(str); str->append(')'); } @@ -4054,7 +4054,7 @@ enum Item_result Item_func_get_user_var::result_type() const void Item_func_get_user_var::print(String *str) { - str->append("(@", 2); + str->append(STRING_WITH_LEN("(@")); str->append(name.str,name.length); str->append(')'); } @@ -4479,15 +4479,15 @@ double Item_func_match::val_real() void Item_func_match::print(String *str) { - str->append("(match ", 7); + str->append(STRING_WITH_LEN("(match ")); print_args(str, 1); - str->append(" against (", 10); + str->append(STRING_WITH_LEN(" against (")); args[0]->print(str); if (flags & FT_BOOL) - str->append(" in boolean mode", 16); + str->append(STRING_WITH_LEN(" in boolean mode")); else if (flags & FT_EXPAND) - str->append(" with query expansion", 21); - str->append("))", 2); + str->append(STRING_WITH_LEN(" with query expansion")); + str->append(STRING_WITH_LEN("))")); } longlong Item_func_bit_xor::val_int() @@ -4690,10 +4690,16 @@ Item_func_sp::sp_result_field(void) const { Field *field; DBUG_ENTER("Item_func_sp::sp_result_field"); + DBUG_PRINT("info", ("sp: %s, flags: %x, level: %lu", + (m_sp ? "YES" : "NO"), + (m_sp ? m_sp->m_flags : (uint)0), + (m_sp ? m_sp->m_recursion_level : (ulong)0))); if (!m_sp) { - if (!(m_sp= sp_find_function(current_thd, m_name, TRUE))) + THD *thd= current_thd; + if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, + &thd->sp_func_cache, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); DBUG_RETURN(0); @@ -4919,7 +4925,8 @@ Item_func_sp::find_and_check_access(THD *thd, ulong want_access, bool res= TRUE; *save= 0; // Safety if error - if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) + if (! m_sp && ! (m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, + &thd->sp_func_cache, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); goto error; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 772d441f2ea..2343502cf48 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1790,7 +1790,7 @@ String *Item_func_format::val_str(String *str) void Item_func_format::print(String *str) { - str->append("format(", 7); + str->append(STRING_WITH_LEN("format(")); args[0]->print(str); str->append(','); // my_charset_bin is good enough for numbers @@ -1950,7 +1950,7 @@ String *Item_func_make_set::val_str(String *str) void Item_func_make_set::print(String *str) { - str->append("make_set(", 9); + str->append(STRING_WITH_LEN("make_set(")); item->print(str); if (arg_count) { @@ -2331,9 +2331,9 @@ void Item_func_conv_charset::fix_length_and_dec() void Item_func_conv_charset::print(String *str) { - str->append("convert(", 8); + str->append(STRING_WITH_LEN("convert(")); args[0]->print(str); - str->append(" using ", 7); + str->append(STRING_WITH_LEN(" using ")); str->append(conv_charset->csname); str->append(')'); } @@ -2403,7 +2403,7 @@ void Item_func_set_collation::print(String *str) { str->append('('); args[0]->print(str); - str->append(" collate ", 9); + str->append(STRING_WITH_LEN(" collate ")); DBUG_ASSERT(args[1]->basic_const_item() && args[1]->type() == Item::STRING_ITEM); args[1]->str_value.print(str); @@ -2523,9 +2523,9 @@ String *Item_func_unhex::val_str(String *str) void Item_func_binary::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as binary)", 11); + str->append(STRING_WITH_LEN(" as binary)")); } @@ -2630,7 +2630,7 @@ String* Item_func_export_set::val_str(String* str) } break; case 3: - sep_buf.set(",", 1, default_charset()); + sep_buf.set(STRING_WITH_LEN(","), default_charset()); sep = &sep_buf; break; default: @@ -2745,7 +2745,8 @@ String *Item_func_quote::val_str(String *str) uint arg_length, new_length; if (!arg) // Null argument { - str->copy("NULL", 4, collation.collation); // Return the string 'NULL' + /* Return the string 'NULL' */ + str->copy(STRING_WITH_LEN("NULL"), collation.collation); null_value= 0; return str; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b78b7d64430..88620634354 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -533,7 +533,7 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): void Item_exists_subselect::print(String *str) { - str->append("exists", 6); + str->append(STRING_WITH_LEN("exists")); Item_subselect::print(str); } @@ -1343,11 +1343,11 @@ err: void Item_in_subselect::print(String *str) { if (transformed) - str->append("<exists>", 8); + str->append(STRING_WITH_LEN("<exists>")); else { left_expr->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); } Item_subselect::print(str); } @@ -1366,7 +1366,7 @@ Item_allany_subselect::select_transformer(JOIN *join) void Item_allany_subselect::print(String *str) { if (transformed) - str->append("<exists>", 8); + str->append(STRING_WITH_LEN("<exists>")); else { left_expr->print(str); @@ -1798,16 +1798,16 @@ void subselect_union_engine::print(String *str) void subselect_uniquesubquery_engine::print(String *str) { - str->append("<primary_index_lookup>(", 23); + str->append(STRING_WITH_LEN("<primary_index_lookup>(")); tab->ref.items[0]->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name); KEY *key_info= tab->table->key_info+ tab->ref.key; - str->append(" on ", 4); + str->append(STRING_WITH_LEN(" on ")); str->append(key_info->name); if (cond) { - str->append(" where ", 7); + str->append(STRING_WITH_LEN(" where ")); cond->print(str); } str->append(')'); @@ -1816,18 +1816,18 @@ void subselect_uniquesubquery_engine::print(String *str) void subselect_indexsubquery_engine::print(String *str) { - str->append("<index_lookup>(", 15); + str->append(STRING_WITH_LEN("<index_lookup>(")); tab->ref.items[0]->print(str); - str->append(" in ", 4); + str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name); KEY *key_info= tab->table->key_info+ tab->ref.key; - str->append(" on ", 4); + str->append(STRING_WITH_LEN(" on ")); str->append(key_info->name); if (check_null) - str->append(" checking NULL", 14); + str->append(STRING_WITH_LEN(" checking NULL")); if (cond) { - str->append(" where ", 7); + str->append(STRING_WITH_LEN(" where ")); cond->print(str); } str->append(')'); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 1013804d393..e38f5ca94bb 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3380,9 +3380,9 @@ String* Item_func_group_concat::val_str(String* str) void Item_func_group_concat::print(String *str) { - str->append("group_concat(", 13); + str->append(STRING_WITH_LEN("group_concat(")); if (distinct) - str->append("distinct ", 9); + str->append(STRING_WITH_LEN("distinct ")); for (uint i= 0; i < arg_count_field; i++) { if (i) @@ -3391,19 +3391,19 @@ void Item_func_group_concat::print(String *str) } if (arg_count_order) { - str->append(" order by ", 10); + str->append(STRING_WITH_LEN(" order by ")); for (uint i= 0 ; i < arg_count_order ; i++) { if (i) str->append(','); (*order[i]->item)->print(str); if (order[i]->asc) - str->append(" ASC"); + str->append(STRING_WITH_LEN(" ASC")); else - str->append(" DESC"); + str->append(STRING_WITH_LEN(" DESC")); } } - str->append(" separator \'", 12); + str->append(STRING_WITH_LEN(" separator \'")); str->append(*separator); - str->append("\')", 2); + str->append(STRING_WITH_LEN("\')")); } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 2b0314bb287..61449d3c671 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -506,7 +506,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, str->set_charset(&my_charset_bin); if (l_time->neg) - str->append("-", 1); + str->append('-'); end= (ptr= format->format.str) + format->format.length; for (; ptr != end ; ptr++) @@ -546,21 +546,21 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, length= int10_to_str(l_time->day, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); if (l_time->day >= 10 && l_time->day <= 19) - str->append("th", 2); + str->append(STRING_WITH_LEN("th")); else { switch (l_time->day %10) { case 1: - str->append("st",2); + str->append(STRING_WITH_LEN("st")); break; case 2: - str->append("nd",2); + str->append(STRING_WITH_LEN("nd")); break; case 3: - str->append("rd",2); + str->append(STRING_WITH_LEN("rd")); break; default: - str->append("th",2); + str->append(STRING_WITH_LEN("th")); break; } } @@ -2142,9 +2142,9 @@ void Item_date_add_interval::print(String *str) void Item_extract::print(String *str) { - str->append("extract(", 8); + str->append(STRING_WITH_LEN("extract(")); str->append(interval_names[int_type]); - str->append(" from ", 6); + str->append(STRING_WITH_LEN(" from ")); args[0]->print(str); str->append(')'); } @@ -2286,9 +2286,9 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const void Item_typecast::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as ", 4); + str->append(STRING_WITH_LEN(" as ")); str->append(cast_type()); str->append(')'); } @@ -2296,9 +2296,9 @@ void Item_typecast::print(String *str) void Item_char_typecast::print(String *str) { - str->append("cast(", 5); + str->append(STRING_WITH_LEN("cast(")); args[0]->print(str); - str->append(" as char", 8); + str->append(STRING_WITH_LEN(" as char")); if (cast_length >= 0) { str->append('('); @@ -2311,7 +2311,7 @@ void Item_char_typecast::print(String *str) } if (cast_cs) { - str->append(" charset ", 9); + str->append(STRING_WITH_LEN(" charset ")); str->append(cast_cs->csname); } str->append(')'); @@ -2352,22 +2352,37 @@ String *Item_char_typecast::val_str(String *str) and the result is longer than cast length, e.g. CAST('string' AS CHAR(1)) */ - if (cast_length >= 0 && - (res->length() > (length= (uint32) res->charpos(cast_length)))) - { // Safe even if const arg - char char_type[40]; - my_snprintf(char_type, sizeof(char_type), "CHAR(%lu)", length); - - if (!res->alloced_length()) - { // Don't change const str - str_value= *res; // Not malloced string - res= &str_value; + if (cast_length >= 0) + { + if (res->length() > (length= (uint32) res->charpos(cast_length))) + { // Safe even if const arg + char char_type[40]; + my_snprintf(char_type, sizeof(char_type), "%s(%lu)", + cast_cs == &my_charset_bin ? "BINARY" : "CHAR", length); + + if (!res->alloced_length()) + { // Don't change const str + str_value= *res; // Not malloced string + res= &str_value; + } + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), char_type, + res->c_ptr_safe()); + res->length((uint) length); + } + else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length) + { + if (res->alloced_length() < (uint) cast_length) + { + str->alloc(cast_length); + str->copy(*res); + res= str; + } + bzero((char*) res->ptr() + res->length(), + (uint) cast_length - res->length()); + res->length(cast_length); } - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), char_type, - res->c_ptr_safe()); - res->length((uint) length); } null_value= 0; return res; @@ -2609,14 +2624,14 @@ void Item_func_add_time::print(String *str) if (is_date) { DBUG_ASSERT(sign > 0); - str->append("timestamp(", 10); + str->append(STRING_WITH_LEN("timestamp(")); } else { if (sign > 0) - str->append("addtime(", 8); + str->append(STRING_WITH_LEN("addtime(")); else - str->append("subtime(", 8); + str->append(STRING_WITH_LEN("subtime(")); } args[0]->print(str); str->append(','); @@ -2825,31 +2840,31 @@ void Item_func_timestamp_diff::print(String *str) switch (int_type) { case INTERVAL_YEAR: - str->append("YEAR"); + str->append(STRING_WITH_LEN("YEAR")); break; case INTERVAL_QUARTER: - str->append("QUARTER"); + str->append(STRING_WITH_LEN("QUARTER")); break; case INTERVAL_MONTH: - str->append("MONTH"); + str->append(STRING_WITH_LEN("MONTH")); break; case INTERVAL_WEEK: - str->append("WEEK"); + str->append(STRING_WITH_LEN("WEEK")); break; case INTERVAL_DAY: - str->append("DAY"); + str->append(STRING_WITH_LEN("DAY")); break; case INTERVAL_HOUR: - str->append("HOUR"); + str->append(STRING_WITH_LEN("HOUR")); break; case INTERVAL_MINUTE: - str->append("MINUTE"); + str->append(STRING_WITH_LEN("MINUTE")); break; case INTERVAL_SECOND: - str->append("SECOND"); + str->append(STRING_WITH_LEN("SECOND")); break; case INTERVAL_MICROSECOND: - str->append("SECOND_FRAC"); + str->append(STRING_WITH_LEN("SECOND_FRAC")); break; default: break; @@ -2905,13 +2920,13 @@ void Item_func_get_format::print(String *str) switch (type) { case MYSQL_TIMESTAMP_DATE: - str->append("DATE, "); + str->append(STRING_WITH_LEN("DATE, ")); break; case MYSQL_TIMESTAMP_DATETIME: - str->append("DATETIME, "); + str->append(STRING_WITH_LEN("DATETIME, ")); break; case MYSQL_TIMESTAMP_TIME: - str->append("TIME, "); + str->append(STRING_WITH_LEN("TIME, ")); break; default: DBUG_ASSERT(0); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index c884c454dac..a0aa0b96cc6 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -29,7 +29,7 @@ public: :Item_real_func(list) {} double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } - void print(String *str) { str->append("0.0", 3); } + void print(String *str) { str->append(STRING_WITH_LEN("0.0")); } const char *func_name() const { return "unique_users"; } }; @@ -57,7 +57,7 @@ public: { return new Item_sum_unique_users(thd, this); } - void print(String *str) { str->append("0.0", 3); } + void print(String *str) { str->append(STRING_WITH_LEN("0.0")); } Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); const char *func_name() const { return "sum_unique_users"; } }; diff --git a/sql/key.cc b/sql/key.cc index 4bd71d2fa47..9d86095f33e 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -322,7 +322,7 @@ void key_unpack(String *to,TABLE *table,uint idx) { if (table->record[0][key_part->null_offset] & key_part->null_bit) { - to->append("NULL", 4); + to->append(STRING_WITH_LEN("NULL")); continue; } } @@ -334,7 +334,7 @@ void key_unpack(String *to,TABLE *table,uint idx) to->append(tmp); } else - to->append("???", 3); + to->append(STRING_WITH_LEN("???")); } DBUG_VOID_RETURN; } diff --git a/sql/lex.h b/sql/lex.h index a5366742fd9..efcb9b84f81 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -110,6 +110,7 @@ static SYMBOL symbols[] = { { "CIPHER", SYM(CIPHER_SYM)}, { "CLIENT", SYM(CLIENT_SYM)}, { "CLOSE", SYM(CLOSE_SYM)}, + { "CODE", SYM(CODE_SYM)}, { "COLLATE", SYM(COLLATE_SYM)}, { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, diff --git a/sql/log.cc b/sql/log.cc index e42f1def27c..6c37cb04c61 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -131,7 +131,7 @@ static int binlog_commit(THD *thd, bool all) // we're here because trans_log was flushed in MYSQL_LOG::log() DBUG_RETURN(0); } - Query_log_event qev(thd, "COMMIT", 6, TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); } @@ -155,7 +155,7 @@ static int binlog_rollback(THD *thd, bool all) */ if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE)) { - Query_log_event qev(thd, "ROLLBACK", 8, TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); error= binlog_end_trans(thd, trans_log, &qev); } else @@ -1821,7 +1821,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) */ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - Query_log_event qinfo(thd, "BEGIN", 5, TRUE, FALSE); + Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE); /* Imagine this is rollback due to net timeout, after all statements of the transaction succeeded. Then we want a zero-error code in BEGIN. diff --git a/sql/log_event.cc b/sql/log_event.cc index 2390ebd4214..056bcca1a02 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -160,7 +160,7 @@ static void cleanup_load_tmpdir() we cannot meet Start_log event in the middle of events from one LOAD DATA. */ - p= strmake(prefbuf,"SQL_LOAD-",9); + p= strmake(prefbuf, STRING_WITH_LEN("SQL_LOAD-")); p= int10_to_str(::server_id, p, 10); *(p++)= '-'; *p= 0; @@ -901,14 +901,16 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) /* Pretty-print event common header if header is exactly 19 bytes */ if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN) { + DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); 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]); + (unsigned long) 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; } @@ -925,8 +927,10 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) if (i % 16 == 15) { + DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); fprintf(file, "# %8.8lx %-48.48s |%16s|\n", - hexdump_from + (i & 0xfffffff0), hex_string, char_string); + (unsigned long) (hexdump_from + (i & 0xfffffff0)), + hex_string, char_string); hex_string[0]= 0; char_string[0]= 0; c= char_string; @@ -938,8 +942,10 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) /* Non-full last line */ if (hex_string[0]) { - printf("# %8.8lx %-48.48s |%s|\n# ", - hexdump_from + (i & 0xfffffff0), hex_string, char_string); + DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); + fprintf(file, "# %8.8lx %-48.48s |%s|\n# ", + (unsigned long) (hexdump_from + (i & 0xfffffff0)), + hex_string, char_string); } } } @@ -2991,7 +2997,7 @@ void Rotate_log_event::pack_info(Protocol *protocol) String tmp(buf1, sizeof(buf1), log_cs); tmp.length(0); tmp.append(new_log_ident, ident_len); - tmp.append(";pos="); + tmp.append(STRING_WITH_LEN(";pos=")); tmp.append(llstr(pos,buf)); protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin); } @@ -4163,7 +4169,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) bzero((char*)&file, sizeof(file)); p = slave_load_file_stem(fname_buf, file_id, server_id); strmov(p, ".info"); // strmov takes less code than memcpy - strnmov(proc_info, "Making temp file ", 17); // no end 0 + strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0 thd->proc_info= proc_info; my_delete(fname_buf, MYF(0)); // old copy may exist already if ((fd= my_create(fname_buf, CREATE_MODE, @@ -4332,7 +4338,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) DBUG_ENTER("Append_block_log_event::exec_event"); memcpy(p, ".data", 6); - strnmov(proc_info, "Making temp file ", 17); // no end 0 + strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0 thd->proc_info= proc_info; if (get_create_or_append()) { @@ -4816,23 +4822,23 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli) p= buf; memcpy(p, query, fn_pos_start); p+= fn_pos_start; - fname= (p= strmake(p, " INFILE \'", 9)); + fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'"))); p= slave_load_file_stem(p, file_id, server_id); - fname_end= (p= strmake(p, ".data", 5)); + fname_end= (p= strmake(p, STRING_WITH_LEN(".data"))); *(p++)='\''; switch (dup_handling) { case LOAD_DUP_IGNORE: - p= strmake(p, " IGNORE", 7); + p= strmake(p, STRING_WITH_LEN(" IGNORE")); break; case LOAD_DUP_REPLACE: - p= strmake(p, " REPLACE", 8); + p= strmake(p, STRING_WITH_LEN(" REPLACE")); break; default: /* Ordinary load data */ break; } - p= strmake(p, " INTO", 5); + p= strmake(p, STRING_WITH_LEN(" INTO")); p= strmake(p, query+fn_pos_end, q_len-fn_pos_end); error= Query_log_event::exec_event(rli, buf, p-buf); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b22330152e8..b5b95e48889 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -496,6 +496,8 @@ pthread_cond_t COND_refresh,COND_thread_count; pthread_t signal_thread; pthread_attr_t connection_attrib; +File_parser_dummy_hook file_parser_dummy_hook; + /* replication parameters, if master_host is not NULL, we are a slave */ uint master_port= MYSQL_PORT, master_connect_retry = 60; uint report_port= MYSQL_PORT; @@ -4543,6 +4545,7 @@ enum options_mysqld OPT_OPTIMIZER_PRUNE_LEVEL, OPT_UPDATABLE_VIEWS_WITH_LIMIT, OPT_SP_AUTOMATIC_PRIVILEGES, + OPT_MAX_SP_RECURSION_DEPTH, OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET, OPT_ENABLE_LARGE_PAGES, OPT_TIMED_MUTEXES, @@ -5758,6 +5761,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.read_buff_size, (gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0}, + {"max_sp_recursion_depth", OPT_MAX_SP_RECURSION_DEPTH, + "Maximum stored procedure recursion depth. (discussed with docs).", + (gptr*) &global_system_variables.max_sp_recursion_depth, + (gptr*) &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG, + OPT_ARG, 0, 0, 255, 0, 1, 0 }, #ifdef HAVE_REPLICATION {"relay_log_purge", OPT_RELAY_LOG_PURGE, "0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.", diff --git a/sql/opt_range.cc b/sql/opt_range.cc index de52811c12f..323e829f219 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6691,7 +6691,7 @@ void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str) QUICK_RANGE_SELECT *quick; bool first= TRUE; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); - str->append("sort_union("); + str->append(STRING_WITH_LEN("sort_union(")); while ((quick= it++)) { if (!first) @@ -6713,7 +6713,7 @@ void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str) bool first= TRUE; QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); - str->append("intersect("); + str->append(STRING_WITH_LEN("intersect(")); while ((quick= it++)) { KEY *key_info= head->key_info + quick->index; @@ -6737,7 +6737,7 @@ void QUICK_ROR_UNION_SELECT::add_info_string(String *str) bool first= TRUE; QUICK_SELECT_I *quick; List_iterator_fast<QUICK_SELECT_I> it(quick_selects); - str->append("union("); + str->append(STRING_WITH_LEN("union(")); while ((quick= it++)) { if (!first) @@ -8868,7 +8868,7 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, } } if (!tmp.length()) - tmp.append("(empty)"); + tmp.append(STRING_WITH_LEN("(empty)")); DBUG_PRINT("info", ("SEL_TREE %p (%s) scans:%s", tree, msg, tmp.ptr())); @@ -8894,7 +8894,7 @@ static void print_ror_scans_arr(TABLE *table, const char *msg, tmp.append(table->key_info[(*start)->keynr].name); } if (!tmp.length()) - tmp.append("(empty)"); + tmp.append(STRING_WITH_LEN("(empty)")); DBUG_PRINT("info", ("ROR key scans (%s): %s", msg, tmp.ptr())); DBUG_VOID_RETURN; } diff --git a/sql/parse_file.cc b/sql/parse_file.cc index d3e5645bafc..69757e0be06 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -50,23 +50,23 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s) */ switch(*ptr) { case '\\': // escape character - if (my_b_append(file, (const byte *)"\\\\", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\\"))) return TRUE; break; case '\n': // parameter value delimiter - if (my_b_append(file, (const byte *)"\\n", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\n"))) return TRUE; break; case '\0': // problem for some string processing utilities - if (my_b_append(file, (const byte *)"\\0", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\0"))) return TRUE; break; case 26: // problem for windows utilities (Ctrl-Z) - if (my_b_append(file, (const byte *)"\\z", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\z"))) return TRUE; break; case '\'': // list of string delimiter - if (my_b_append(file, (const byte *)"\\\'", 2)) + if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\'"))) return TRUE; break; default: @@ -155,10 +155,10 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, while ((str= it++)) { // We need ' ' after string to detect list continuation - if ((!first && my_b_append(file, (const byte *)" ", 1)) || - my_b_append(file, (const byte *)"\'", 1) || + if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) || + my_b_append(file, (const byte *)STRING_WITH_LEN("\'")) || write_escaped_string(file, str) || - my_b_append(file, (const byte *)"\'", 1)) + my_b_append(file, (const byte *)STRING_WITH_LEN("\'"))) { DBUG_RETURN(TRUE); } @@ -176,7 +176,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, { num.set(*val, &my_charset_bin); // We need ' ' after string to detect list continuation - if ((!first && my_b_append(file, (const byte *)" ", 1)) || + if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) || my_b_append(file, (const byte *)num.ptr(), num.length())) { DBUG_RETURN(TRUE); @@ -242,9 +242,9 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, goto err_w_file; // write header (file signature) - if (my_b_append(&file, (const byte *)"TYPE=", 5) || + if (my_b_append(&file, (const byte *)STRING_WITH_LEN("TYPE=")) || my_b_append(&file, (const byte *)type->str, type->length) || - my_b_append(&file, (const byte *)"\n", 1)) + my_b_append(&file, (const byte *)STRING_WITH_LEN("\n"))) goto err_w_file; // write parameters to temporary file @@ -252,9 +252,9 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, { if (my_b_append(&file, (const byte *)param->name.str, param->name.length) || - my_b_append(&file, (const byte *)"=", 1) || + my_b_append(&file, (const byte *)STRING_WITH_LEN("=")) || write_parameter(&file, base, param, &old_version) || - my_b_append(&file, (const byte *)"\n", 1)) + my_b_append(&file, (const byte *)STRING_WITH_LEN("\n"))) goto err_w_cache; } @@ -664,6 +664,61 @@ parse_quoted_escaped_string(char *ptr, char *end, /* + Parser for FILE_OPTIONS_ULLLIST type value. + + SYNOPSIS + get_file_options_ulllist() + ptr [in/out] pointer to parameter + end [in] end of the configuration + line [in] pointer to the line begining + base [in] base address for parameter writing (structure + like TABLE) + parameter [in] description + mem_root [in] MEM_ROOT for parameters allocation +*/ + +bool get_file_options_ulllist(char *&ptr, char *end, char *line, + gptr base, File_option *parameter, + MEM_ROOT *mem_root) +{ + List<ulonglong> *nlist= (List<ulonglong>*)(base + parameter->offset); + ulonglong *num; + nlist->empty(); + // list parsing + while (ptr < end) + { + int not_used; + char *num_end= end; + if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) || + nlist->push_back(num, mem_root)) + goto nlist_err; + *num= my_strtoll10(ptr, &num_end, ¬_used); + ptr= num_end; + switch (*ptr) { + case '\n': + goto end_of_nlist; + case ' ': + // we cant go over buffer bounds, because we have \0 at the end + ptr++; + break; + default: + goto nlist_err_w_message; + } + } + +end_of_nlist: + if (*(ptr++) != '\n') + goto nlist_err; + return FALSE; + +nlist_err_w_message: + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), parameter->name.str, line); +nlist_err: + return TRUE; +} + + +/* parse parameters SYNOPSIS @@ -673,6 +728,8 @@ parse_quoted_escaped_string(char *ptr, char *end, mem_root MEM_ROOT for parameters allocation parameters parameters description required number of required parameters in above list + hook hook called for unknown keys + hook_data some data specific for the hook RETURN FALSE - OK @@ -681,15 +738,15 @@ parse_quoted_escaped_string(char *ptr, char *end, my_bool File_parser::parse(gptr base, MEM_ROOT *mem_root, - struct File_option *parameters, uint required) + struct File_option *parameters, uint required, + Unknown_key_hook *hook) { uint first_param= 0, found= 0; - register char *ptr= start; + char *ptr= start; char *eol; LEX_STRING *str; List<LEX_STRING> *list; ulonglong *num; - List<ulonglong> *nlist; DBUG_ENTER("File_parser::parse"); while (ptr < end && found < required) @@ -829,58 +886,64 @@ list_err: DBUG_RETURN(TRUE); } case FILE_OPTIONS_ULLLIST: - { - nlist= (List<ulonglong>*)(base + parameter->offset); - nlist->empty(); - // list parsing - while (ptr < end) - { - int not_used; - char *num_end= end; - if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) || - nlist->push_back(num, mem_root)) - goto nlist_err; - *num= my_strtoll10(ptr, &num_end, ¬_used); - ptr= num_end; - switch (*ptr) { - case '\n': - goto end_of_nlist; - case ' ': - // we cant go over buffer bounds, because we have \0 at the end - ptr++; - break; - default: - goto nlist_err_w_message; - } - } - -end_of_nlist: - if (*(ptr++) != '\n') - goto nlist_err; + if (get_file_options_ulllist(ptr, end, line, base, + parameter, mem_root)) + DBUG_RETURN(TRUE); break; - -nlist_err_w_message: - my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), - parameter->name.str, line); -nlist_err: - DBUG_RETURN(TRUE); - - } default: DBUG_ASSERT(0); // never should happened } } else { - // skip unknown parameter - if (!(ptr= strchr(ptr, '\n'))) - { - my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), line); - DBUG_RETURN(TRUE); - } - ptr++; + ptr= line; + if (hook->process_unknown_string(ptr, base, mem_root, end)) + { + DBUG_RETURN(TRUE); + } + // skip unknown parameter + if (!(ptr= strchr(ptr, '\n'))) + { + my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), line); + DBUG_RETURN(TRUE); + } + ptr++; } } } DBUG_RETURN(FALSE); } + + +/* + Dummy unknown key hook + + SYNOPSIS + File_parser_dummy_hook::process_unknown_string() + unknown_key [in/out] reference on the line with unknown + parameter and the parsing point + base [in] base address for parameter writing (structure like + TABLE) + mem_root [in] MEM_ROOT for parameters allocation + end [in] the end of the configuration + + NOTE + This hook used to catch no longer supported keys and process them for + backward compatibility, but it will not slow down processing of modern + format files. + This hook does nothing except debug output. + + RETURN + FALSE OK + TRUE Error +*/ + +bool +File_parser_dummy_hook::process_unknown_string(char *&unknown_key, + gptr base, MEM_ROOT *mem_root, + char *end) +{ + DBUG_ENTER("file_parser_dummy_hook::process_unknown_string"); + DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + DBUG_RETURN(FALSE); +} diff --git a/sql/parse_file.h b/sql/parse_file.h index b4199e4fbf1..afa88da2ead 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -40,6 +40,35 @@ struct File_option file_opt_type type; /* Option type */ }; + +/* + This hook used to catch no longer supported keys and process them for + backward compatibility. +*/ + +class Unknown_key_hook +{ +public: + virtual bool process_unknown_string(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, char *end)= 0; +}; + + +/* Dummy hook for parsers which do not need hook for unknown keys */ + +class File_parser_dummy_hook: public Unknown_key_hook +{ +public: + virtual bool process_unknown_string(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, char *end); +}; + +extern File_parser_dummy_hook file_parser_dummy_hook; + +bool get_file_options_ulllist(char *&ptr, char *end, char *line, + gptr base, File_option *parameter, + MEM_ROOT *mem_root); + class File_parser; File_parser *sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root, bool bad_format_errors); @@ -64,7 +93,8 @@ public: my_bool ok() { return content_ok; } LEX_STRING *type() { return &file_type; } my_bool parse(gptr base, MEM_ROOT *mem_root, - struct File_option *parameters, uint required); + struct File_option *parameters, uint required, + Unknown_key_hook *hook); friend File_parser *sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root, diff --git a/sql/protocol.cc b/sql/protocol.cc index 8c3e5a62820..0a1b42f5236 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -498,7 +498,7 @@ void Protocol::init(THD *thd_arg) thd=thd_arg; packet= &thd->packet; convert= &thd->convert_buffer; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_types= 0; #endif } @@ -551,7 +551,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); } -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_types= (enum_field_types*) thd->alloc(sizeof(field_types) * list->elements); uint count= 0; @@ -572,7 +572,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (prot.store("def", 3, cs, thd_charset) || + if (prot.store(STRING_WITH_LEN("def"), cs, thd_charset) || prot.store(field.db_name, (uint) strlen(field.db_name), cs, thd_charset) || prot.store(field.table_name, (uint) strlen(field.table_name), @@ -648,7 +648,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) item->send(&prot, &tmp); // Send default value if (prot.write()) break; /* purecov: inspected */ -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_types[count++]= field.type; #endif } @@ -732,14 +732,14 @@ bool Protocol::store(I_List<i_string>* str_list) void Protocol_simple::prepare_for_resend() { packet->length(0); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_pos= 0; #endif } bool Protocol_simple::store_null() { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_pos++; #endif char buff[1]; @@ -773,7 +773,7 @@ bool Protocol::store_string_aux(const char *from, uint length, bool Protocol_simple::store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || @@ -790,7 +790,7 @@ bool Protocol_simple::store(const char *from, uint length, CHARSET_INFO *fromcs) { CHARSET_INFO *tocs= this->thd->variables.character_set_results; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || @@ -805,7 +805,7 @@ bool Protocol_simple::store(const char *from, uint length, bool Protocol_simple::store_tiny(longlong from) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY); field_pos++; #endif @@ -817,7 +817,7 @@ bool Protocol_simple::store_tiny(longlong from) bool Protocol_simple::store_short(longlong from) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_YEAR || field_types[field_pos] == MYSQL_TYPE_SHORT); @@ -831,7 +831,7 @@ bool Protocol_simple::store_short(longlong from) bool Protocol_simple::store_long(longlong from) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_INT24 || field_types[field_pos] == MYSQL_TYPE_LONG); @@ -845,7 +845,7 @@ bool Protocol_simple::store_long(longlong from) bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_LONGLONG); field_pos++; @@ -860,7 +860,7 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) bool Protocol_simple::store_decimal(const my_decimal *d) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; @@ -874,7 +874,7 @@ bool Protocol_simple::store_decimal(const my_decimal *d) bool Protocol_simple::store(float from, uint32 decimals, String *buffer) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_FLOAT); field_pos++; @@ -886,7 +886,7 @@ bool Protocol_simple::store(float from, uint32 decimals, String *buffer) bool Protocol_simple::store(double from, uint32 decimals, String *buffer) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DOUBLE); field_pos++; @@ -900,7 +900,7 @@ bool Protocol_simple::store(Field *field) { if (field->is_null()) return store_null(); -#ifndef DEBUG_OFF +#ifndef DBUG_OFF field_pos++; #endif char buff[MAX_FIELD_WIDTH]; @@ -921,7 +921,7 @@ bool Protocol_simple::store(Field *field) bool Protocol_simple::store(TIME *tm) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DATETIME || field_types[field_pos] == MYSQL_TYPE_TIMESTAMP); @@ -944,7 +944,7 @@ bool Protocol_simple::store(TIME *tm) bool Protocol_simple::store_date(TIME *tm) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DATE); field_pos++; @@ -963,7 +963,7 @@ bool Protocol_simple::store_date(TIME *tm) bool Protocol_simple::store_time(TIME *tm) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TIME); field_pos++; @@ -1088,7 +1088,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) bool Protocol_prep::store_decimal(const my_decimal *d) { -#ifndef DEBUG_OFF +#ifndef DBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; diff --git a/sql/protocol.h b/sql/protocol.h index c00bbba4cc9..8d9da5774b2 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -31,7 +31,7 @@ protected: String *packet; String *convert; uint field_pos; -#ifndef DEBUG_OFF +#ifndef DBUG_OFF enum enum_field_types *field_types; #endif uint field_count; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 2f00e43deec..d76be2ec2e4 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -502,7 +502,7 @@ int update_slave_list(MYSQL* mysql, MASTER_INFO* mi) int port_ind; DBUG_ENTER("update_slave_list"); - if (mysql_real_query(mysql,"SHOW SLAVE HOSTS",16) || + if (mysql_real_query(mysql, STRING_WITH_LEN("SHOW SLAVE HOSTS")) || !(res = mysql_store_result(mysql))) { error= mysql_error(mysql); @@ -795,7 +795,7 @@ bool load_master_data(THD* thd) MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res; uint num_dbs; - if (mysql_real_query(&mysql, "SHOW DATABASES", 14) || + if (mysql_real_query(&mysql, STRING_WITH_LEN("SHOW DATABASES")) || !(db_res = mysql_store_result(&mysql))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); @@ -821,8 +821,9 @@ bool load_master_data(THD* thd) we wait to issue FLUSH TABLES WITH READ LOCK for as long as we can to minimize the lock time. */ - if (mysql_real_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) || - mysql_real_query(&mysql, "SHOW MASTER STATUS",18) || + if (mysql_real_query(&mysql, + STRING_WITH_LEN("FLUSH TABLES WITH READ LOCK")) || + mysql_real_query(&mysql, STRING_WITH_LEN("SHOW MASTER STATUS")) || !(master_status_res = mysql_store_result(&mysql))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); @@ -875,7 +876,7 @@ bool load_master_data(THD* thd) } if (mysql_select_db(&mysql, db) || - mysql_real_query(&mysql, "SHOW TABLES", 11) || + mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) || !(*cur_table_res = mysql_store_result(&mysql))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); @@ -933,7 +934,7 @@ bool load_master_data(THD* thd) mysql_free_result(master_status_res); } - if (mysql_real_query(&mysql, "UNLOCK TABLES", 13)) + if (mysql_real_query(&mysql, STRING_WITH_LEN("UNLOCK TABLES"))) { my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql)); goto err; diff --git a/sql/set_var.cc b/sql/set_var.cc index 89ad00d7839..632c37d2296 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -261,6 +261,8 @@ sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size", fix_max_relay_log_size); sys_var_thd_ulong sys_max_sort_length("max_sort_length", &SV::max_sort_length); +sys_var_thd_ulong sys_max_sp_recursion_depth("max_sp_recursion_depth", + &SV::max_sp_recursion_depth); sys_var_max_user_conn sys_max_user_connections("max_user_connections"); sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables", &SV::max_tmp_tables); @@ -631,6 +633,7 @@ sys_var *sys_variables[]= &sys_max_relay_log_size, &sys_max_seeks_for_key, &sys_max_sort_length, + &sys_max_sp_recursion_depth, &sys_max_tmp_tables, &sys_max_user_connections, &sys_max_write_lock_count, @@ -896,6 +899,8 @@ struct show_var_st init_vars[]= { {sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS}, {sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, + {sys_max_sp_recursion_depth.name, + (char*) &sys_max_sp_recursion_depth, SHOW_SYS}, {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index 2e23027f1f5..6d905ba35dc 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -49,5 +49,15 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README $(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets +# FIXME maybe shouldn't remove, could be needed by other installation? +uninstall-local: + @RM@ -f -r $(DESTDIR)$(pkgdatadir) + +distclean-local: + @RM@ -f */errmsg.sys + +# Do nothing +link_sources: + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a25d1196904..d0773e8af3b 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5361,7 +5361,7 @@ ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG ER_NO_DEFAULT_FOR_VIEW_FIELD eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value" ER_SP_NO_RECURSION - eng "Recursive stored routines are not allowed." + eng "Recursive stored functions and triggers are not allowed." ER_TOO_BIG_SCALE 42000 S1009 eng "Too big scale %d specified for column '%-.64s'. Maximum is %d." ER_TOO_BIG_PRECISION 42000 S1009 @@ -5423,3 +5423,7 @@ ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" ER_TRG_NO_DEFINER eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger." +ER_OLD_FILE_FORMAT + eng "'%-.64s' has an old format, you should re-create the '%s' object(s)" +ER_SP_RECURSION_LIMIT + eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s" diff --git a/sql/slave.cc b/sql/slave.cc index 82d9799fec9..065d9c787ce 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1397,7 +1397,7 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi) MYSQL_RES *master_res= 0; MYSQL_ROW master_row; - if (!mysql_real_query(mysql, "SELECT UNIX_TIMESTAMP()", 23) && + if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) && (master_res= mysql_store_result(mysql)) && (master_row= mysql_fetch_row(master_res))) { @@ -1423,7 +1423,8 @@ do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS"); Note: we could have put a @@SERVER_ID in the previous SELECT UNIX_TIMESTAMP() instead, but this would not have worked on 3.23 masters. */ - if (!mysql_real_query(mysql, "SHOW VARIABLES LIKE 'SERVER_ID'", 31) && + if (!mysql_real_query(mysql, + STRING_WITH_LEN("SHOW VARIABLES LIKE 'SERVER_ID'")) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -1458,7 +1459,8 @@ not always make sense; please check the manual before using it)."; goto err; if ((*mysql->server_version == '4') && - !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) && + !mysql_real_query(mysql, + STRING_WITH_LEN("SELECT @@GLOBAL.COLLATION_SERVER")) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -1485,7 +1487,7 @@ be equal for replication to work"; those were alpha). */ if ((*mysql->server_version == '4') && - !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && + !mysql_real_query(mysql, STRING_WITH_LEN("SELECT @@GLOBAL.TIME_ZONE")) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && diff --git a/sql/sp.cc b/sql/sp.cc index 451cec75236..8991cc78b5e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -29,6 +29,11 @@ create_string(THD *thd, String *buf, const char *returns, ulong returnslen, const char *body, ulong bodylen, st_sp_chistics *chistics); +static int +db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, + ulong sql_mode, const char *params, const char *returns, + const char *body, st_sp_chistics &chistics, + const char *definer, longlong created, longlong modified); /* * @@ -377,83 +382,80 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) close_proc_table(thd, &open_tables_state_backup); table= 0; - { - String defstr; - LEX *oldlex= thd->lex; - char olddb[128]; - bool dbchanged; - enum enum_sql_command oldcmd= thd->lex->sql_command; - ulong old_sql_mode= thd->variables.sql_mode; - ha_rows select_limit= thd->variables.select_limit; - - thd->variables.sql_mode= sql_mode; - thd->variables.select_limit= HA_POS_ERROR; - - defstr.set_charset(system_charset_info); - if (!create_string(thd, &defstr, - type, - name, - params, strlen(params), - returns, strlen(returns), - body, strlen(body), - &chistics)) - { - ret= SP_INTERNAL_ERROR; - goto done; - } + ret= db_load_routine(thd, type, name, sphp, + sql_mode, params, returns, body, chistics, + definer, created, modified); + + done: + if (table) + close_proc_table(thd, &open_tables_state_backup); + DBUG_RETURN(ret); +} - dbchanged= FALSE; - if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), - 1, &dbchanged))) - goto done; - { - /* This is something of a kludge. We need to initialize some fields - * in thd->lex (the unit and master stuff), and the easiest way to - * do it is, is to call mysql_init_query(), but this unfortunately - * resets teh value_list where we keep the CALL parameters. So we - * copy the list and then restore it. (... and found_semicolon too). - */ - List<Item> tmpvals= thd->lex->value_list; - char *tmpfsc= thd->lex->found_semicolon; - - lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); - thd->lex->value_list= tmpvals; - thd->lex->found_semicolon= tmpfsc; - } +static int +db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, + ulong sql_mode, const char *params, const char *returns, + const char *body, st_sp_chistics &chistics, + const char *definer, longlong created, longlong modified) +{ + LEX *oldlex= thd->lex, newlex; + sp_rcontext *save_spcont= thd->spcont; + String defstr; + char olddb[128]; + bool dbchanged; + ulong old_sql_mode= thd->variables.sql_mode; + ha_rows select_limit= thd->variables.select_limit; + int ret= SP_INTERNAL_ERROR; + + thd->variables.sql_mode= sql_mode; + thd->variables.select_limit= HA_POS_ERROR; + + thd->lex= &newlex; + newlex.current_select= NULL; + + defstr.set_charset(system_charset_info); + if (!create_string(thd, &defstr, + type, + name, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), + &chistics)) + goto end; - if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL) - { - LEX *newlex= thd->lex; - sp_head *sp= newlex->sphead; + dbchanged= FALSE; + if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), + 1, &dbchanged))) + goto end; - if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto done; - if (sp) - { - delete sp; - newlex->sphead= NULL; - } - ret= SP_PARSE_ERROR; - } - else - { - if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) - goto done; - *sphp= thd->lex->sphead; - (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); - (*sphp)->set_info(created, modified, &chistics, sql_mode); - (*sphp)->optimize(); - } - thd->lex->sql_command= oldcmd; - thd->variables.sql_mode= old_sql_mode; - thd->variables.select_limit= select_limit; - } + lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); - done: - if (table) - close_proc_table(thd, &open_tables_state_backup); - DBUG_RETURN(ret); + thd->spcont= 0; + if (yyparse(thd) || thd->is_fatal_error || newlex.sphead == NULL) + { + sp_head *sp= newlex.sphead; + + if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) + goto end; + delete sp; + ret= SP_PARSE_ERROR; + } + else + { + if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) + goto end; + *sphp= newlex.sphead; + (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); + (*sphp)->set_info(created, modified, &chistics, sql_mode); + (*sphp)->optimize(); + } +end: + thd->spcont= save_spcont; + thd->variables.sql_mode= old_sql_mode; + thd->variables.select_limit= select_limit; + thd->lex= oldlex; + return ret; } @@ -899,45 +901,106 @@ err: ******************************************************************************/ /* - Obtain object representing stored procedure by its name from + Obtain object representing stored procedure/function by its name from stored procedures cache and looking into mysql.proc if needed. SYNOPSIS - sp_find_procedure() + sp_find_routine() thd - thread context + type - type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE) name - name of procedure + cp - hash to look routine in cache_only - if true perform cache-only lookup (Don't look in mysql.proc). - TODO - We should consider merging of sp_find_procedure() and - sp_find_function() into one sp_find_routine() function - (the same applies to other similarly paired functions). - RETURN VALUE Non-0 pointer to sp_head object for the procedure, or 0 - in case of error. */ sp_head * -sp_find_procedure(THD *thd, sp_name *name, bool cache_only) +sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, + bool cache_only) { sp_head *sp; - DBUG_ENTER("sp_find_procedure"); - DBUG_PRINT("enter", ("name: %.*s.%.*s", - name->m_db.length, name->m_db.str, - name->m_name.length, name->m_name.str)); + ulong depth= (type == TYPE_ENUM_PROCEDURE ? + thd->variables.max_sp_recursion_depth : + 0); + + DBUG_ENTER("sp_find_routine"); + DBUG_PRINT("enter", ("name: %.*s.%.*s, type: %d, cache only %d", + name->m_db.length, name->m_db.str, + name->m_name.length, name->m_name.str, + type, cache_only)); - if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only) + if ((sp= sp_cache_lookup(cp, name))) + { + ulong level; + DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); + if (sp->m_first_free_instance) + { + DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x", + (ulong)sp->m_first_free_instance, + sp->m_first_free_instance->m_recursion_level, + sp->m_first_free_instance->m_flags)); + DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED)); + if (sp->m_first_free_instance->m_recursion_level > depth) + { + sp->recursion_level_error(); + DBUG_RETURN(0); + } + DBUG_RETURN(sp->m_first_free_instance); + } + level= sp->m_last_cached_sp->m_recursion_level + 1; + if (level > depth) + { + sp->recursion_level_error(); + DBUG_RETURN(0); + } + { + sp_head *new_sp; + const char *returns= ""; + char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + String retstr(64); + strxmov(definer, sp->m_definer_user.str, "@", + sp->m_definer_host.str, NullS); + if (type == TYPE_ENUM_FUNCTION) + { + sp_returns_type(thd, retstr, sp); + returns= retstr.ptr(); + } + if (db_load_routine(thd, type, name, &new_sp, + sp->m_sql_mode, sp->m_params.str, returns, + sp->m_body.str, *sp->m_chistics, definer, + sp->m_created, sp->m_modified) == SP_OK) + { + sp->m_last_cached_sp->m_next_cached_sp= new_sp; + new_sp->m_recursion_level= level; + new_sp->m_first_instance= sp; + sp->m_last_cached_sp= sp->m_first_free_instance= new_sp; + DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x", + (ulong)new_sp, new_sp->m_recursion_level, + new_sp->m_flags)); + DBUG_RETURN(new_sp); + } + DBUG_RETURN(0); + } + } + if (!cache_only) { - if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK) - sp_cache_insert(&thd->sp_proc_cache, sp); + if (db_find_routine(thd, type, name, &sp) == SP_OK) + { + sp_cache_insert(cp, sp); + DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x", + (ulong)sp, sp->m_recursion_level, + sp->m_flags)); + } } - DBUG_RETURN(sp); } + int sp_exists_routine(THD *thd, TABLE_LIST *tables, bool any, bool no_error) { @@ -955,8 +1018,10 @@ sp_exists_routine(THD *thd, TABLE_LIST *tables, bool any, bool no_error) lex_name.str= thd->strmake(table->table_name, lex_name.length); name= new sp_name(lex_db, lex_name); name->init_qname(thd); - if (sp_find_procedure(thd, name) != NULL || - sp_find_function(thd, name) != NULL) + if (sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name, + &thd->sp_proc_cache, FALSE) != NULL || + sp_find_routine(thd, TYPE_ENUM_FUNCTION, name, + &thd->sp_func_cache, FALSE) != NULL) { if (any) DBUG_RETURN(1); @@ -1024,7 +1089,8 @@ sp_show_create_procedure(THD *thd, sp_name *name) DBUG_ENTER("sp_show_create_procedure"); DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); - if ((sp= sp_find_procedure(thd, name))) + if ((sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name, + &thd->sp_proc_cache, FALSE))) { int ret= sp->show_create_procedure(thd); @@ -1050,42 +1116,6 @@ sp_show_status_procedure(THD *thd, const char *wild) FUNCTION ******************************************************************************/ -/* - Obtain object representing stored function by its name from - stored functions cache and looking into mysql.proc if needed. - - SYNOPSIS - sp_find_function() - thd - thread context - name - name of function - cache_only - if true perform cache-only lookup - (Don't look in mysql.proc). - - NOTE - See TODO section for sp_find_procedure(). - - RETURN VALUE - Non-0 pointer to sp_head object for the function, or - 0 - in case of error. -*/ - -sp_head * -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)); - - if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) && - !cache_only) - { - if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) == SP_OK) - sp_cache_insert(&thd->sp_func_cache, sp); - } - DBUG_RETURN(sp); -} - - int sp_create_function(THD *thd, sp_head *sp) { @@ -1133,7 +1163,8 @@ sp_show_create_function(THD *thd, sp_name *name) DBUG_ENTER("sp_show_create_function"); DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str)); - if ((sp= sp_find_function(thd, name))) + if ((sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, name, + &thd->sp_func_cache, FALSE))) { int ret= sp->show_create_function(thd); @@ -1443,10 +1474,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, &thd->sp_func_cache : &thd->sp_proc_cache), &name))) { - LEX *oldlex= thd->lex; - LEX *newlex= new st_lex; - thd->lex= newlex; - newlex->current_select= NULL; name.m_name.str= strchr(name.m_qname.str, '.'); name.m_db.length= name.m_name.str - name.m_qname.str; name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str, @@ -1461,8 +1488,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, else sp_cache_insert(&thd->sp_proc_cache, sp); } - delete newlex; - thd->lex= oldlex; } if (sp) { @@ -1585,30 +1610,30 @@ create_string(THD *thd, String *buf, chistics->comment.length)) return FALSE; - buf->append("CREATE ", 7); + buf->append(STRING_WITH_LEN("CREATE ")); if (type == TYPE_ENUM_FUNCTION) - buf->append("FUNCTION ", 9); + buf->append(STRING_WITH_LEN("FUNCTION ")); else - buf->append("PROCEDURE ", 10); + buf->append(STRING_WITH_LEN("PROCEDURE ")); append_identifier(thd, buf, name->m_name.str, name->m_name.length); buf->append('('); buf->append(params, paramslen); buf->append(')'); if (type == TYPE_ENUM_FUNCTION) { - buf->append(" RETURNS ", 9); + buf->append(STRING_WITH_LEN(" RETURNS ")); buf->append(returns, returnslen); } buf->append('\n'); switch (chistics->daccess) { case SP_NO_SQL: - buf->append(" NO SQL\n"); + buf->append(STRING_WITH_LEN(" NO SQL\n")); break; case SP_READS_SQL_DATA: - buf->append(" READS SQL DATA\n"); + buf->append(STRING_WITH_LEN(" READS SQL DATA\n")); break; case SP_MODIFIES_SQL_DATA: - buf->append(" MODIFIES SQL DATA\n"); + buf->append(STRING_WITH_LEN(" MODIFIES SQL DATA\n")); break; case SP_DEFAULT_ACCESS: case SP_CONTAINS_SQL: @@ -1616,12 +1641,12 @@ create_string(THD *thd, String *buf, break; } if (chistics->detistic) - buf->append(" DETERMINISTIC\n", 18); + buf->append(STRING_WITH_LEN(" DETERMINISTIC\n")); if (chistics->suid == SP_IS_NOT_SUID) - buf->append(" SQL SECURITY INVOKER\n", 25); + buf->append(STRING_WITH_LEN(" SQL SECURITY INVOKER\n")); if (chistics->comment.length) { - buf->append(" COMMENT "); + buf->append(STRING_WITH_LEN(" COMMENT ")); append_unescaped(buf, chistics->comment.str, chistics->comment.length); buf->append('\n'); } @@ -36,7 +36,8 @@ int sp_drop_db_routines(THD *thd, char *db); sp_head * -sp_find_procedure(THD *thd, sp_name *name, bool cache_only = 0); +sp_find_routine(THD *thd, int type, sp_name *name, + sp_cache **cp, bool cache_only); int sp_exists_routine(THD *thd, TABLE_LIST *procs, bool any, bool no_error); @@ -57,9 +58,6 @@ sp_show_create_procedure(THD *thd, sp_name *name); int sp_show_status_procedure(THD *thd, const char *wild); -sp_head * -sp_find_function(THD *thd, sp_name *name, bool cache_only = 0); - int sp_create_function(THD *thd, sp_head *sp); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6248a60521b..a6e88c08789 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -105,6 +105,8 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_VARIABLES: case SQLCOM_SHOW_WARNS: + case SQLCOM_SHOW_PROC_CODE: + case SQLCOM_SHOW_FUNC_CODE: flags= sp_head::MULTI_RESULTS; break; /* @@ -476,7 +478,8 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), - m_flags(0), m_returns_cs(NULL) + m_flags(0), m_returns_cs(NULL), m_recursion_level(0), m_next_cached_sp(0), + m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); @@ -657,6 +660,7 @@ sp_head::create(THD *thd) sp_head::~sp_head() { destroy(); + delete m_next_cached_sp; if (m_thd) restore_thd_mem_root(m_thd); } @@ -858,9 +862,9 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length; /* append the spvar substitute */ - res|= qbuf.append(" NAME_CONST('"); + res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('")); res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length); - res|= qbuf.append("',"); + res|= qbuf.append(STRING_WITH_LEN("',")); val= (*splocal)->this_item(); DBUG_PRINT("info", ("print %p", val)); val->print(&qbuf); @@ -883,6 +887,31 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) /* + Return appropriate error about recursion limit reaching + + SYNOPSIS + sp_head::recursion_level_error() + + NOTE + For functions and triggers we return error about prohibited recursion. + For stored procedures we return about reaching recursion limit. +*/ + +void sp_head::recursion_level_error() +{ + if (m_type == TYPE_ENUM_PROCEDURE) + { + THD *thd= current_thd; + my_error(ER_SP_RECURSION_LIMIT, MYF(0), + thd->variables.max_sp_recursion_depth, + m_name); + } + else + my_error(ER_SP_NO_RECURSION, MYF(0)); +} + + +/* Execute the routine. The main instruction jump loop is there Assume the parameters already set. @@ -911,37 +940,31 @@ int sp_head::execute(THD *thd) Item_change_list old_change_list; String old_packet; - /* init per-instruction memroot */ - init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - - /* Use some extra margin for possible SP recursion and functions */ - if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb)) + if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet)) { DBUG_RETURN(-1); } - if (m_flags & IS_INVOKED) - { - /* - We have to disable recursion for stored routines since in - many cases LEX structure and many Item's can't be used in - reentrant way now. - - TODO: We can circumvent this problem by using separate - sp_head instances for each recursive invocation. - - NOTE: Theoretically arguments of procedure can be evaluated - before its invocation so there should be no problem with - recursion. But since we perform cleanup for CALL statement - as for any other statement only after its execution, its LEX - structure is not reusable for recursive calls. Thus we have - to prohibit recursion for stored procedures too. - */ - my_error(ER_SP_NO_RECURSION, MYF(0)); - DBUG_RETURN(-1); - } + /* init per-instruction memroot */ + init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + + DBUG_ASSERT(!(m_flags & IS_INVOKED)); m_flags|= IS_INVOKED; + m_first_instance->m_first_free_instance= m_next_cached_sp; + DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x", + (ulong)m_first_instance, this, m_next_cached_sp, + m_next_cached_sp->m_recursion_level, + m_next_cached_sp->m_flags)); + /* + Check that if there are not any instances after this one then + pointer to the last instance points on this instance or if there are + some instances after this one then recursion level of next instance + greater then recursion level of current instance on 1 + */ + DBUG_ASSERT((m_next_cached_sp == 0 && + m_first_instance->m_last_cached_sp == this) || + (m_recursion_level + 1 == m_next_cached_sp->m_recursion_level)); dbchanged= FALSE; if (m_db.length && @@ -1116,6 +1139,29 @@ int sp_head::execute(THD *thd) ret= mysql_change_db(thd, olddb, 1); } m_flags&= ~IS_INVOKED; + DBUG_PRINT("info", ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x", + (ulong)m_first_instance, + m_first_instance->m_first_free_instance, this, + m_recursion_level, m_flags)); + /* + Check that we have one of following: + + 1) there are not free instances which means that this instance is last + in the list of instances (pointer to the last instance point on it and + ther are not other instances after this one in the list) + + 2) There are some free instances which mean that first free instance + should go just after this one and recursion level of that free instance + should be on 1 more then recursion leven of this instance. + */ + DBUG_ASSERT((m_first_instance->m_first_free_instance == 0 && + this == m_first_instance->m_last_cached_sp && + m_next_cached_sp == 0) || + (m_first_instance->m_first_free_instance != 0 && + m_first_instance->m_first_free_instance == m_next_cached_sp && + m_first_instance->m_first_free_instance->m_recursion_level == + m_recursion_level + 1)); + m_first_instance->m_first_free_instance= this; DBUG_RETURN(ret); } @@ -1173,6 +1219,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) // QQ Should have some error checking here? (types, etc...) if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax))) goto end; +#ifndef DBUG_OFF + nctx->owner= this; +#endif for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); @@ -1215,7 +1264,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) char buf[256]; String bufstr(buf, sizeof(buf), &my_charset_bin); bufstr.length(0); - bufstr.append("DO ", 3); + bufstr.append(STRING_WITH_LEN("DO ")); append_identifier(thd, &bufstr, m_name.str, m_name.length); bufstr.append('('); for (uint i=0; i < argcount; i++) @@ -1317,6 +1366,9 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) { // Create a temporary old context if (!(octx= new sp_rcontext(octx, csize, hmax, cmax))) DBUG_RETURN(-1); +#ifndef DBUG_OFF + octx->owner= 0; +#endif thd->spcont= octx; /* set callers_arena to thd, for upper-level function to work */ @@ -1328,6 +1380,9 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args) thd->spcont= save_spcont; DBUG_RETURN(-1); } +#ifndef DBUG_OFF + nctx->owner= this; +#endif if (csize > 0 || hmax > 0 || cmax > 0) { @@ -1740,7 +1795,7 @@ sp_head::show_create_procedure(THD *thd) LINT_INIT(sql_mode_len); if (check_show_routine_access(thd, this, &full_access)) - return 1; + DBUG_RETURN(1); sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, @@ -1753,10 +1808,7 @@ sp_head::show_create_procedure(THD *thd) max(buffer.length(), 1024))); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - { - res= 1; - goto done; - } + DBUG_RETURN(1); protocol->prepare_for_resend(); protocol->store(m_name.str, m_name.length, system_charset_info); protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); @@ -1765,7 +1817,6 @@ sp_head::show_create_procedure(THD *thd) res= protocol->write(); send_eof(thd); - done: DBUG_RETURN(res); } @@ -1810,7 +1861,7 @@ sp_head::show_create_function(THD *thd) LINT_INIT(sql_mode_len); if (check_show_routine_access(thd, this, &full_access)) - return 1; + DBUG_RETURN(1); sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, @@ -1822,10 +1873,7 @@ sp_head::show_create_function(THD *thd) max(buffer.length(),1024))); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - { - res= 1; - goto done; - } + DBUG_RETURN(1); protocol->prepare_for_resend(); protocol->store(m_name.str, m_name.length, system_charset_info); protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); @@ -1834,7 +1882,6 @@ sp_head::show_create_function(THD *thd) res= protocol->write(); send_eof(thd); - done: DBUG_RETURN(res); } @@ -1894,6 +1941,50 @@ sp_head::opt_mark(uint ip) } +#ifndef DBUG_OFF +int +sp_head::show_routine_code(THD *thd) +{ + Protocol *protocol= thd->protocol; + char buff[2048]; + String buffer(buff, sizeof(buff), system_charset_info); + List<Item> field_list; + sp_instr *i; + bool full_access; + int res= 0; + uint ip; + DBUG_ENTER("sp_head::show_routine_code"); + DBUG_PRINT("info", ("procedure: %s", m_name.str)); + + if (check_show_routine_access(thd, this, &full_access) || !full_access) + DBUG_RETURN(1); + + field_list.push_back(new Item_uint("Pos", 9)); + // 1024 is for not to confuse old clients + field_list.push_back(new Item_empty_string("Instruction", + max(buffer.length(), 1024))); + if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | + Protocol::SEND_EOF)) + DBUG_RETURN(1); + + for (ip= 0; (i = get_instr(ip)) ; ip++) + { + protocol->prepare_for_resend(); + protocol->store((longlong)ip); + + buffer.set("", 0, system_charset_info); + i->print(&buffer); + protocol->store(buffer.ptr(), buffer.length(), system_charset_info); + if ((res= protocol->write())) + break; + } + send_eof(thd); + + DBUG_RETURN(res); +} +#endif // ifndef DBUG_OFF + + /* Prepare LEX and thread for execution of instruction, if requested open and lock LEX's tables, execute instruction's core function, perform @@ -2052,14 +2143,43 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } +/* + Sufficient max length of printed destinations and frame offsets (all uints). +*/ +#define SP_INSTR_UINT_MAXLEN 8 + +#define SP_STMT_PRINT_MAXLEN 40 void sp_instr_stmt::print(String *str) { - str->reserve(12); - str->append("stmt "); + uint i, len; + + /* stmt CMD "..." */ + if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8)) + return; + str->qs_append(STRING_WITH_LEN("stmt ")); str->qs_append((uint)m_lex_keeper.sql_command()); + str->qs_append(STRING_WITH_LEN(" \"")); + len= m_query.length; + /* + Print the query string (but not too much of it), just to indicate which + statement it is. + */ + if (len > SP_STMT_PRINT_MAXLEN) + len= SP_STMT_PRINT_MAXLEN-3; + /* Copy the query string and replace '\n' with ' ' in the process */ + for (i= 0 ; i < len ; i++) + { + if (m_query.str[i] == '\n') + str->qs_append(' '); + else + str->qs_append(m_query.str[i]); + } + if (m_query.length > SP_STMT_PRINT_MAXLEN) + str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */ + str->qs_append('"'); } - +#undef SP_STMT_PRINT_MAXLEN int sp_instr_stmt::exec_core(THD *thd, uint *nextp) @@ -2096,10 +2216,23 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) void sp_instr_set::print(String *str) { - str->reserve(12); - str->append("set "); + /* set name@offset ... */ + int rsrv = SP_INSTR_UINT_MAXLEN+6; + sp_pvar_t *var = m_ctx->find_pvar(m_offset); + + /* 'var' should always be non-null, but just in case... */ + if (var) + rsrv+= var->name.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("set ")); + if (var) + { + str->qs_append(var->name.str, var->name.length); + str->qs_append('@'); + } str->qs_append(m_offset); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2132,9 +2265,9 @@ sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) void sp_instr_set_trigger_field::print(String *str) { - str->append("set ", 4); + str->append(STRING_WITH_LEN("set_trigger_field ")); trigger_field->print(str); - str->append(":=", 2); + str->append(STRING_WITH_LEN(":=")); value->print(str); } @@ -2156,8 +2289,10 @@ sp_instr_jump::execute(THD *thd, uint *nextp) void sp_instr_jump::print(String *str) { - str->reserve(12); - str->append("jump "); + /* jump dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) + return; + str->qs_append(STRING_WITH_LEN("jump ")); str->qs_append(m_dest); } @@ -2238,10 +2373,12 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if::print(String *str) { - str->reserve(12); - str->append("jump_if "); + /* jump_if dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too + return; + str->qs_append(STRING_WITH_LEN("jump_if ")); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2299,10 +2436,12 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - str->reserve(16); - str->append("jump_if_not "); + /* jump_if_not dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too + return; + str->qs_append(STRING_WITH_LEN("jump_if_not ")); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2357,10 +2496,12 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) void sp_instr_freturn::print(String *str) { - str->reserve(12); - str->append("freturn "); + /* freturn type expr... */ + if (str->reserve(UINT_MAX+8+32)) // Add some for the expr. too + return; + str->qs_append(STRING_WITH_LEN("freturn ")); str->qs_append((uint)m_type); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2385,15 +2526,31 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) void sp_instr_hpush_jump::print(String *str) { - str->reserve(32); - str->append("hpush_jump "); + /* hpush_jump dest fsize type */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21)) + return; + str->qs_append(STRING_WITH_LEN("hpush_jump ")); str->qs_append(m_dest); - str->append(" t="); - str->qs_append(m_type); - str->append(" f="); + str->qs_append(' '); str->qs_append(m_frame); - str->append(" h="); - str->qs_append(m_ip+1); + switch (m_type) + { + case SP_HANDLER_NONE: + str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug + break; + case SP_HANDLER_EXIT: + str->qs_append(STRING_WITH_LEN(" EXIT")); + break; + case SP_HANDLER_CONTINUE: + str->qs_append(STRING_WITH_LEN(" CONTINUE")); + break; + case SP_HANDLER_UNDO: + str->qs_append(STRING_WITH_LEN(" UNDO")); + break; + default: + str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); // This would be a bug as well + str->qs_append(m_type); + } } uint @@ -2428,8 +2585,10 @@ sp_instr_hpop::execute(THD *thd, uint *nextp) void sp_instr_hpop::print(String *str) { - str->reserve(12); - str->append("hpop "); + /* hpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) + return; + str->qs_append(STRING_WITH_LEN("hpop ")); str->qs_append(m_count); } @@ -2463,12 +2622,14 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) void sp_instr_hreturn::print(String *str) { - str->reserve(16); - str->append("hreturn "); + /* hreturn framesize dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9)) + return; + str->qs_append(STRING_WITH_LEN("hreturn ")); str->qs_append(m_frame); if (m_dest) { - str->append(' '); + str->qs_append(' '); str->qs_append(m_dest); } } @@ -2516,7 +2677,22 @@ sp_instr_cpush::execute(THD *thd, uint *nextp) void sp_instr_cpush::print(String *str) { - str->append("cpush"); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cpush name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+7; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("cpush ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } + str->qs_append(m_cursor); } @@ -2537,8 +2713,10 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) void sp_instr_cpop::print(String *str) { - str->reserve(12); - str->append("cpop "); + /* cpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) + return; + str->qs_append(STRING_WITH_LEN("cpop ")); str->qs_append(m_count); } @@ -2612,8 +2790,21 @@ sp_instr_copen::exec_core(THD *thd, uint *nextp) void sp_instr_copen::print(String *str) { - str->reserve(12); - str->append("copen "); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* copen name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+7; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("copen ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } str->qs_append(m_cursor); } @@ -2641,8 +2832,21 @@ sp_instr_cclose::execute(THD *thd, uint *nextp) void sp_instr_cclose::print(String *str) { - str->reserve(12); - str->append("cclose "); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cclose name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+8; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("cclose ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } str->qs_append(m_cursor); } @@ -2671,14 +2875,29 @@ sp_instr_cfetch::print(String *str) { List_iterator_fast<struct sp_pvar> li(m_varlist); sp_pvar_t *pv; - - str->reserve(12); - str->append("cfetch "); + LEX_STRING n; + my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cfetch name@offset vars... */ + uint rsrv= SP_INSTR_UINT_MAXLEN+8; + + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append(STRING_WITH_LEN("cfetch ")); + if (found) + { + str->qs_append(n.str, n.length); + str->qs_append('@'); + } str->qs_append(m_cursor); while ((pv= li++)) { - str->reserve(8); - str->append(' '); + if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) + return; + str->qs_append(' '); + str->qs_append(pv->name.str, pv->name.length); + str->qs_append('@'); str->qs_append(pv->offset); } } @@ -2702,8 +2921,10 @@ sp_instr_error::execute(THD *thd, uint *nextp) void sp_instr_error::print(String *str) { - str->reserve(12); - str->append("error "); + /* error code */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+6)) + return; + str->qs_append(STRING_WITH_LEN("error ")); str->qs_append(m_errcode); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 8c2d58a696e..6334bca0fc6 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -143,6 +143,32 @@ public: LEX_STRING m_definer_host; longlong m_created; longlong m_modified; + /* Recursion level of the current SP instance. The levels are numbered from 0 */ + ulong m_recursion_level; + /* + A list of diferent recursion level instances for the same procedure. + For every recursion level we have a sp_head instance. This instances + connected in the list. The list ordered by increasing recursion level + (m_recursion_level). + */ + sp_head *m_next_cached_sp; + /* + Pointer to the first element of the above list + */ + sp_head *m_first_instance; + /* + Pointer to the first free (non-INVOKED) routine in the list of + cached instances for this SP. This pointer is set only for the first + SP in the list of instences (see above m_first_cached_sp pointer). + The pointer equal to 0 if we have no free instances. + For non-first instance value of this pointer meanless (point to itself); + */ + sp_head *m_first_free_instance; + /* + Pointer to the last element in the list of instances of the SP. + For non-first instance value of this pointer meanless (point to itself); + */ + sp_head *m_last_cached_sp; /* Set containing names of stored routines used by this routine. Note that unlike elements of similar set for statement elements of this @@ -266,6 +292,8 @@ public: void optimize(); void opt_mark(uint ip); + void recursion_level_error(); + inline sp_instr * get_instr(uint i) { @@ -304,6 +332,12 @@ public: return test(m_flags & (CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT)); } + +#ifndef DBUG_OFF + int show_routine_code(THD *thd); +#endif + + private: MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root @@ -865,8 +899,8 @@ class sp_instr_cpush : public sp_instr public: - sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex) - : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE) + sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex, uint offset) + : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE), m_cursor(offset) {} virtual ~sp_instr_cpush() @@ -885,6 +919,7 @@ public: private: sp_lex_keeper m_lex_keeper; + uint m_cursor; /* Frame offset (for debugging) */ }; // class sp_instr_cpush : public sp_instr diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index f873b676925..147173ab4d8 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -169,6 +169,28 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) return NULL; } +/* + Find a variable by offset from the top. + This used for two things: + - When evaluating parameters at the beginning, and setting out parameters + at the end, of invokation. (Top frame only, so no recursion then.) + - For printing of sp_instr_set. (Debug mode only.) + */ +sp_pvar_t * +sp_pcontext::find_pvar(uint offset) +{ + if (m_poffset <= offset && offset < m_poffset + m_pvar.elements) + { // This frame + sp_pvar_t *p; + + get_dynamic(&m_pvar, (gptr)&p, offset - m_poffset); + return p; + } + if (m_parent) + return m_parent->find_pvar(offset); // Some previous frame + return NULL; // index out of bounds +} + void sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode) @@ -331,3 +353,21 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) return m_parent->find_cursor(name, poff, scoped); return FALSE; } + +/* + Find a cursor by offset from the top. + This is only used for debugging. + */ +my_bool +sp_pcontext::find_cursor(uint offset, LEX_STRING *n) +{ + if (m_coffset <= offset && offset < m_coffset + m_cursor.elements) + { // This frame + get_dynamic(&m_cursor, (gptr)n, offset - m_coffset); + return TRUE; + } + if (m_parent) + return m_parent->find_cursor(offset, n); // Some previous frame + return FALSE; // index out of bounds +} + diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index bd2259cb6fb..b8dd1742f7e 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -170,18 +170,9 @@ class sp_pcontext : public Sql_alloc sp_pvar_t * find_pvar(LEX_STRING *name, my_bool scoped=0); - // Find by index + // Find by offset sp_pvar_t * - find_pvar(uint i) - { - sp_pvar_t *p; - - if (i < m_pvar.elements) - get_dynamic(&m_pvar, (gptr)&p, i); - else - p= NULL; - return p; - } + find_pvar(uint offset); // // Labels @@ -261,6 +252,10 @@ class sp_pcontext : public Sql_alloc my_bool find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0); + /* Find by offset (for debugging only) */ + my_bool + find_cursor(uint offset, LEX_STRING *n); + inline uint max_cursors() { diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index cae5c5467c9..d54188aa96f 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -66,6 +66,14 @@ class sp_rcontext : public Sql_alloc */ Query_arena *callers_arena; +#ifndef DBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *owner; +#endif + sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax); ~sp_rcontext() diff --git a/sql/spatial.cc b/sql/spatial.cc index ca9615236e0..e91653f79d5 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1793,7 +1793,7 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, geom->set_data_ptr(data, (uint) (m_data_end - data)); if (geom->as_wkt(txt, &data)) return 1; - if (txt->append(",", 1, 512)) + if (txt->append(STRING_WITH_LEN(","), 512)) return 1; } txt->length(txt->length() - 1); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index bc8b9ba2efb..a572f03b575 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1811,19 +1811,22 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, /* We write down SSL related ACL stuff */ switch (lex->ssl_type) { case SSL_TYPE_ANY: - table->field[next_field]->store("ANY", 3, &my_charset_latin1); + table->field[next_field]->store(STRING_WITH_LEN("ANY"), + &my_charset_latin1); table->field[next_field+1]->store("", 0, &my_charset_latin1); table->field[next_field+2]->store("", 0, &my_charset_latin1); table->field[next_field+3]->store("", 0, &my_charset_latin1); break; case SSL_TYPE_X509: - table->field[next_field]->store("X509", 4, &my_charset_latin1); + table->field[next_field]->store(STRING_WITH_LEN("X509"), + &my_charset_latin1); table->field[next_field+1]->store("", 0, &my_charset_latin1); table->field[next_field+2]->store("", 0, &my_charset_latin1); table->field[next_field+3]->store("", 0, &my_charset_latin1); break; case SSL_TYPE_SPECIFIED: - table->field[next_field]->store("SPECIFIED", 9, &my_charset_latin1); + table->field[next_field]->store(STRING_WITH_LEN("SPECIFIED"), + &my_charset_latin1); table->field[next_field+1]->store("", 0, &my_charset_latin1); table->field[next_field+2]->store("", 0, &my_charset_latin1); table->field[next_field+3]->store("", 0, &my_charset_latin1); @@ -4056,13 +4059,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { String global(buff,sizeof(buff),system_charset_info); global.length(0); - global.append("GRANT ",6); + global.append(STRING_WITH_LEN("GRANT ")); want_access= acl_user->access; if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL))) - global.append("ALL PRIVILEGES",14); + global.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!(want_access & ~GRANT_ACL)) - global.append("USAGE",5); + global.append(STRING_WITH_LEN("USAGE")); else { bool found=0; @@ -4072,16 +4075,16 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_access & j) { if (found) - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); found=1; global.append(command_array[counter],command_lengths[counter]); } } } - global.append (" ON *.* TO '",12); + global.append (STRING_WITH_LEN(" ON *.* TO '")); global.append(lex_user->user.str, lex_user->user.length, system_charset_info); - global.append ("'@'",3); + global.append (STRING_WITH_LEN("'@'")); global.append(lex_user->host.str,lex_user->host.length, system_charset_info); global.append ('\''); @@ -4092,23 +4095,23 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) make_password_from_salt(passwd_buff, acl_user->salt); else make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt); - global.append(" IDENTIFIED BY PASSWORD '",25); + global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); global.append(passwd_buff); global.append('\''); } /* "show grants" SSL related stuff */ if (acl_user->ssl_type == SSL_TYPE_ANY) - global.append(" REQUIRE SSL",12); + global.append(STRING_WITH_LEN(" REQUIRE SSL")); else if (acl_user->ssl_type == SSL_TYPE_X509) - global.append(" REQUIRE X509",13); + global.append(STRING_WITH_LEN(" REQUIRE X509")); else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) { int ssl_options = 0; - global.append(" REQUIRE ",9); + global.append(STRING_WITH_LEN(" REQUIRE ")); if (acl_user->x509_issuer) { ssl_options++; - global.append("ISSUER \'",8); + global.append(STRING_WITH_LEN("ISSUER \'")); global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); global.append('\''); } @@ -4116,7 +4119,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { if (ssl_options++) global.append(' '); - global.append("SUBJECT \'",9); + global.append(STRING_WITH_LEN("SUBJECT \'")); global.append(acl_user->x509_subject,strlen(acl_user->x509_subject), system_charset_info); global.append('\''); @@ -4125,7 +4128,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { if (ssl_options++) global.append(' '); - global.append("CIPHER '",8); + global.append(STRING_WITH_LEN("CIPHER '")); global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), system_charset_info); global.append('\''); @@ -4137,9 +4140,9 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) acl_user->user_resource.conn_per_hour || acl_user->user_resource.user_conn)) { - global.append(" WITH",5); + global.append(STRING_WITH_LEN(" WITH")); if (want_access & GRANT_ACL) - global.append(" GRANT OPTION",13); + global.append(STRING_WITH_LEN(" GRANT OPTION")); add_user_option(&global, acl_user->user_resource.questions, "MAX_QUERIES_PER_HOUR"); add_user_option(&global, acl_user->user_resource.updates, @@ -4177,12 +4180,12 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) { String db(buff,sizeof(buff),system_charset_info); db.length(0); - db.append("GRANT ",6); + db.append(STRING_WITH_LEN("GRANT ")); if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL))) - db.append("ALL PRIVILEGES",14); + db.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!(want_access & ~GRANT_ACL)) - db.append("USAGE",5); + db.append(STRING_WITH_LEN("USAGE")); else { int found=0, cnt; @@ -4192,23 +4195,23 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_access & j) { if (found) - db.append(", ",2); + db.append(STRING_WITH_LEN(", ")); found = 1; db.append(command_array[cnt],command_lengths[cnt]); } } } - db.append (" ON ",4); + db.append (STRING_WITH_LEN(" ON ")); append_identifier(thd, &db, acl_db->db, strlen(acl_db->db)); - db.append (".* TO '",7); + db.append (STRING_WITH_LEN(".* TO '")); db.append(lex_user->user.str, lex_user->user.length, system_charset_info); - db.append ("'@'",3); + db.append (STRING_WITH_LEN("'@'")); db.append(lex_user->host.str, lex_user->host.length, system_charset_info); db.append ('\''); if (want_access & GRANT_ACL) - db.append(" WITH GRANT OPTION",18); + db.append(STRING_WITH_LEN(" WITH GRANT OPTION")); protocol->prepare_for_resend(); protocol->store(db.ptr(),db.length(),db.charset()); if (protocol->write()) @@ -4241,12 +4244,12 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL; global.length(0); - global.append("GRANT ",6); + global.append(STRING_WITH_LEN("GRANT ")); if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) - global.append("ALL PRIVILEGES",14); + global.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!test_access) - global.append("USAGE",5); + global.append(STRING_WITH_LEN("USAGE")); else { /* Add specific column access */ @@ -4258,7 +4261,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_access & j) { if (found) - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); found= 1; global.append(command_array[counter],command_lengths[counter]); @@ -4282,14 +4285,14 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) */ if (table_access & j) { - global.append(", ", 2); + global.append(STRING_WITH_LEN(", ")); global.append(command_array[counter], command_lengths[counter]); } - global.append(" (",2); + global.append(STRING_WITH_LEN(" (")); } else - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); global.append(grant_column->column, grant_column->key_length, system_charset_info); @@ -4301,21 +4304,21 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } - global.append(" ON ",4); + global.append(STRING_WITH_LEN(" ON ")); append_identifier(thd, &global, grant_table->db, strlen(grant_table->db)); global.append('.'); append_identifier(thd, &global, grant_table->tname, strlen(grant_table->tname)); - global.append(" TO '",5); + global.append(STRING_WITH_LEN(" TO '")); global.append(lex_user->user.str, lex_user->user.length, system_charset_info); - global.append("'@'",3); + global.append(STRING_WITH_LEN("'@'")); global.append(lex_user->host.str,lex_user->host.length, system_charset_info); global.append('\''); if (table_access & GRANT_ACL) - global.append(" WITH GRANT OPTION",18); + global.append(STRING_WITH_LEN(" WITH GRANT OPTION")); protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); if (protocol->write()) @@ -4328,14 +4331,14 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } if (show_routine_grants(thd, lex_user, &proc_priv_hash, - "PROCEDURE", 9, buff, sizeof(buff))) + STRING_WITH_LEN("PROCEDURE"), buff, sizeof(buff))) { error= -1; goto end; } if (show_routine_grants(thd, lex_user, &func_priv_hash, - "FUNCTION", 8, buff, sizeof(buff))) + STRING_WITH_LEN("FUNCTION"), buff, sizeof(buff))) { error= -1; goto end; @@ -4376,10 +4379,10 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, ulong test_access= proc_access & ~GRANT_ACL; global.length(0); - global.append("GRANT ",6); + global.append(STRING_WITH_LEN("GRANT ")); if (!test_access) - global.append("USAGE",5); + global.append(STRING_WITH_LEN("USAGE")); else { /* Add specific procedure access */ @@ -4391,13 +4394,13 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, if (test_access & j) { if (found) - global.append(", ",2); + global.append(STRING_WITH_LEN(", ")); found= 1; global.append(command_array[counter],command_lengths[counter]); } } } - global.append(" ON ",4); + global.append(STRING_WITH_LEN(" ON ")); global.append(type,typelen); global.append(' '); append_identifier(thd, &global, grant_proc->db, @@ -4405,15 +4408,15 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, global.append('.'); append_identifier(thd, &global, grant_proc->tname, strlen(grant_proc->tname)); - global.append(" TO '",5); + global.append(STRING_WITH_LEN(" TO '")); global.append(lex_user->user.str, lex_user->user.length, system_charset_info); - global.append("'@'",3); + global.append(STRING_WITH_LEN("'@'")); global.append(lex_user->host.str,lex_user->host.length, system_charset_info); global.append('\''); if (proc_access & GRANT_ACL) - global.append(" WITH GRANT OPTION",18); + global.append(STRING_WITH_LEN(" WITH GRANT OPTION")); protocol->prepare_for_resend(); protocol->store(global.ptr(),global.length(),global.charset()); if (protocol->write()) @@ -5068,7 +5071,7 @@ static void append_user(String *str, LEX_USER *user) str->append(','); str->append('\''); str->append(user->user.str); - str->append("'@'"); + str->append(STRING_WITH_LEN("'@'")); str->append(user->host.str); str->append('\''); } @@ -5650,7 +5653,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",host,"'",NullS); if (!(want_access & ~GRANT_ACL)) - update_schema_privilege(table, buff, 0, 0, 0, 0, "USAGE", 5, is_grantable); + update_schema_privilege(table, buff, 0, 0, 0, 0, + STRING_WITH_LEN("USAGE"), is_grantable); else { uint priv_id; @@ -5708,7 +5712,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",host,"'",NullS); if (!(want_access & ~GRANT_ACL)) update_schema_privilege(table, buff, acl_db->db, 0, 0, - 0, "USAGE", 5, is_grantable); + 0, STRING_WITH_LEN("USAGE"), is_grantable); else { int cnt; @@ -5768,7 +5772,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS); if (!test_access) update_schema_privilege(table, buff, grant_table->db, grant_table->tname, - 0, 0, "USAGE", 5, is_grantable); + 0, 0, STRING_WITH_LEN("USAGE"), is_grantable); else { ulong j; diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index e1f4b8f6076..0e4198a5114 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -733,13 +733,13 @@ bool analyse::end_of_records() tree_info.found = 0; tree_info.item = (*f)->item; - tmp_str.set("ENUM(", 5,&my_charset_bin); + tmp_str.set(STRING_WITH_LEN("ENUM("),&my_charset_bin); tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info, left_root_right); tmp_str.append(')'); if (!(*f)->nulls) - tmp_str.append(" NOT NULL"); + tmp_str.append(STRING_WITH_LEN(" NOT NULL")); output_str_length = tmp_str.length(); func_items[9]->set(tmp_str.ptr(), tmp_str.length(), tmp_str.charset()); if (result->send_data(result_fields)) @@ -749,35 +749,35 @@ bool analyse::end_of_records() ans.length(0); if (!(*f)->treemem && !(*f)->tree_elements) - ans.append("CHAR(0)", 7); + ans.append(STRING_WITH_LEN("CHAR(0)")); else if ((*f)->item->type() == Item::FIELD_ITEM) { switch (((Item_field*) (*f)->item)->field->real_type()) { case FIELD_TYPE_TIMESTAMP: - ans.append("TIMESTAMP", 9); + ans.append(STRING_WITH_LEN("TIMESTAMP")); break; case FIELD_TYPE_DATETIME: - ans.append("DATETIME", 8); + ans.append(STRING_WITH_LEN("DATETIME")); break; case FIELD_TYPE_DATE: case FIELD_TYPE_NEWDATE: - ans.append("DATE", 4); + ans.append(STRING_WITH_LEN("DATE")); break; case FIELD_TYPE_SET: - ans.append("SET", 3); + ans.append(STRING_WITH_LEN("SET")); break; case FIELD_TYPE_YEAR: - ans.append("YEAR", 4); + ans.append(STRING_WITH_LEN("YEAR")); break; case FIELD_TYPE_TIME: - ans.append("TIME", 4); + ans.append(STRING_WITH_LEN("TIME")); break; case FIELD_TYPE_DECIMAL: - ans.append("DECIMAL", 7); + ans.append(STRING_WITH_LEN("DECIMAL")); // if item is FIELD_ITEM, it _must_be_ Field_num in this case if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill) - ans.append(" ZEROFILL"); + ans.append(STRING_WITH_LEN(" ZEROFILL")); break; default: (*f)->get_opt_type(&ans, rows); @@ -785,7 +785,7 @@ bool analyse::end_of_records() } } if (!(*f)->nulls) - ans.append(" NOT NULL"); + ans.append(STRING_WITH_LEN(" NOT NULL")); func_items[9]->set(ans.ptr(), ans.length(), ans.charset()); if (result->send_data(result_fields)) return -1; @@ -829,18 +829,18 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) sprintf(buff, "BIGINT(%d)", num_info.integers); answer->append(buff, (uint) strlen(buff)); if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0) - answer->append(" UNSIGNED"); + answer->append(STRING_WITH_LEN(" UNSIGNED")); if (num_info.zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } else if (max_length < 256) { if (must_be_blob) { if (item->collation.collation == &my_charset_bin) - answer->append("TINYBLOB", 8); + answer->append(STRING_WITH_LEN("TINYBLOB")); else - answer->append("TINYTEXT", 8); + answer->append(STRING_WITH_LEN("TINYTEXT")); } else if ((max_length * (total_rows - nulls)) < (sum + total_rows)) { @@ -856,23 +856,23 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) else if (max_length < (1L << 16)) { if (item->collation.collation == &my_charset_bin) - answer->append("BLOB", 4); + answer->append(STRING_WITH_LEN("BLOB")); else - answer->append("TEXT", 4); + answer->append(STRING_WITH_LEN("TEXT")); } else if (max_length < (1L << 24)) { if (item->collation.collation == &my_charset_bin) - answer->append("MEDIUMBLOB", 10); + answer->append(STRING_WITH_LEN("MEDIUMBLOB")); else - answer->append("MEDIUMTEXT", 10); + answer->append(STRING_WITH_LEN("MEDIUMTEXT")); } else { if (item->collation.collation == &my_charset_bin) - answer->append("LONGBLOB", 8); + answer->append(STRING_WITH_LEN("LONGBLOB")); else - answer->append("LONGTEXT", 8); + answer->append(STRING_WITH_LEN("LONGTEXT")); } } // field_str::get_opt_type @@ -902,14 +902,14 @@ void field_real::get_opt_type(String *answer, sprintf(buff, "BIGINT(%d)", len); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) - answer->append(" UNSIGNED"); + answer->append(STRING_WITH_LEN(" UNSIGNED")); } else if (item->decimals == NOT_FIXED_DEC) { if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX) - answer->append("FLOAT", 5); + answer->append(STRING_WITH_LEN("FLOAT")); else - answer->append("DOUBLE", 6); + answer->append(STRING_WITH_LEN("DOUBLE")); } else { @@ -926,7 +926,7 @@ void field_real::get_opt_type(String *answer, // a single number shouldn't be zerofill (max_length - (item->decimals + 1)) != 1 && ((Field_num*) ((Item_field*) item)->field)->zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } // field_real::get_opt_type @@ -950,14 +950,14 @@ void field_longlong::get_opt_type(String *answer, sprintf(buff, "BIGINT(%d)", (int) max_length); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) - answer->append(" UNSIGNED"); + answer->append(STRING_WITH_LEN(" UNSIGNED")); // if item is FIELD_ITEM, it _must_be_ Field_num in this class if ((item->type() == Item::FIELD_ITEM) && // a single number shouldn't be zerofill max_length != 1 && ((Field_num*) ((Item_field*) item)->field)->zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } // field_longlong::get_opt_type @@ -982,7 +982,7 @@ void field_ulonglong::get_opt_type(String *answer, // a single number shouldn't be zerofill max_length != 1 && ((Field_num*) ((Item_field*) item)->field)->zerofill) - answer->append(" ZEROFILL"); + answer->append(STRING_WITH_LEN(" ZEROFILL")); } //field_ulonglong::get_opt_type diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5753c51fcf4..49decaa01eb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1088,6 +1088,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, /* find a unused table in the open table cache */ if (refresh) *refresh=0; + + /* an open table operation needs a lot of the stack space */ + if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char *)&alias)) + return 0; + if (thd->killed) DBUG_RETURN(0); key_length= (uint) (strmov(strmov(key, table_list->db)+1, @@ -1200,17 +1205,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, (void) unpack_filename(path, path); if (mysql_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW) { - TABLE tab;// will not be used (because it's VIEW) but have to be passed + /* + Will not be used (because it's VIEW) but has to be passed. + Also we will not free it (because it is a stack variable). + */ + TABLE tab; table= &tab; VOID(pthread_mutex_lock(&LOCK_open)); - if (open_unireg_entry(thd, table, table_list->db, - table_list->table_name, - alias, table_list, mem_root)) - { - table->next=table->prev=table; - free_cache_entry(table); - } - else + if (!open_unireg_entry(thd, table, table_list->db, + table_list->table_name, + alias, table_list, mem_root)) { DBUG_ASSERT(table_list->view != 0); VOID(pthread_mutex_unlock(&LOCK_open)); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 123d16b606d..69a0d6cd05d 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -410,7 +410,7 @@ protected: /* The following functions are only used when debugging - We don't protect these with ifndef DEBUG_OFF to not have to recompile + We don't protect these with ifndef DBUG_OFF to not have to recompile everything if we want to add checks of the cache at some places. */ void wreck(uint line, const char *message); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d5292be422b..ea9b5cee474 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1495,7 +1495,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { my_var *mv= gl++; if (mv->local) - (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset)); + { + Item_splocal *var; + (void)local_vars.push_back(var= new Item_splocal(mv->s, mv->offset)); +#ifndef DEBUG_OFF + var->owner= mv->owner; +#endif + } else { Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item); @@ -1914,6 +1920,7 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) - Value for found_rows() is reset and restored - examined_row_count is added to the total - cuted_fields is added to the total + - new savepoint level is created and destroyed NOTES: Seed for random() is saved for the first! usage of RAND() @@ -1937,6 +1944,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, backup->sent_row_count= sent_row_count; backup->cuted_fields= cuted_fields; backup->client_capabilities= client_capabilities; + backup->savepoints= transaction.savepoints; if (!lex->requires_prelocking() || is_update_query(lex->sql_command)) options&= ~OPTION_BIN_LOG; @@ -1949,6 +1957,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, examined_row_count= 0; sent_row_count= 0; cuted_fields= 0; + transaction.savepoints= 0; #ifndef EMBEDDED_LIBRARY /* Surpress OK packets in case if we will execute statements */ @@ -1959,6 +1968,21 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { + /* + To save resources we want to release savepoints which were created + during execution of function or trigger before leaving their savepoint + level. It is enough to release first savepoint set on this level since + all later savepoints will be released automatically. + */ + if (transaction.savepoints) + { + SAVEPOINT *sv; + for (sv= transaction.savepoints; sv->prev; sv= sv->prev) + {} + /* ha_release_savepoint() never returns error. */ + (void)ha_release_savepoint(this, sv); + } + transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; net.no_send_ok= backup->no_send_ok; diff --git a/sql/sql_class.h b/sql/sql_class.h index 8d6207de5ca..3066f59b9cd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -530,6 +530,7 @@ struct system_variables ulong completion_type; /* Determines which non-standard SQL behaviour should be enabled */ ulong sql_mode; + ulong max_sp_recursion_depth; /* check of key presence in updatable view */ ulong updatable_views_with_limit; ulong default_week_format; @@ -1078,6 +1079,7 @@ public: uint in_sub_stmt; bool enable_slow_log, insert_id_used; my_bool no_send_ok; + SAVEPOINT *savepoints; }; @@ -2071,6 +2073,13 @@ public: class my_var : public Sql_alloc { public: LEX_STRING s; +#ifndef DEBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *owner; +#endif bool local; uint offset; enum_field_types type; diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index fc169fe18e8..89c160cd70a 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -661,11 +661,10 @@ Materialized_cursor::~Materialized_cursor() bool Select_materialize::send_fields(List<Item> &list, uint flags) { - bool rc; DBUG_ASSERT(table == 0); if (create_result_table(unit->thd, unit->get_unit_column_types(), FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, "")) return TRUE; - return rc; + return FALSE; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 98d6e3f9aba..e40c5dc783d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1531,9 +1531,9 @@ void st_select_lex_unit::print(String *str) { if (sl != first_select()) { - str->append(" union ", 7); + str->append(STRING_WITH_LEN(" union ")); if (union_all) - str->append("all ", 4); + str->append(STRING_WITH_LEN("all ")); else if (union_distinct == sl) union_all= TRUE; } @@ -1547,7 +1547,7 @@ void st_select_lex_unit::print(String *str) { if (fake_select_lex->order_list.elements) { - str->append(" order by ", 10); + str->append(STRING_WITH_LEN(" order by ")); fake_select_lex->print_order(str, (ORDER *) fake_select_lex-> order_list.first); @@ -1570,7 +1570,7 @@ void st_select_lex::print_order(String *str, ORDER *order) else (*order->item)->print(str); if (!order->asc) - str->append(" desc", 5); + str->append(STRING_WITH_LEN(" desc")); if (order->next) str->append(','); } @@ -1593,7 +1593,7 @@ void st_select_lex::print_limit(THD *thd, String *str) if (explicit_limit) { - str->append(" limit ", 7); + str->append(STRING_WITH_LEN(" limit ")); if (offset_limit) { offset_limit->print(str); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 11618199e69..4295cac9e7b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -90,6 +90,7 @@ enum enum_sql_command { SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, + SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, /* This should be the last !!! */ SQLCOM_END diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 568778c021d..2a0145af9c7 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -680,7 +680,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, length=(uint) (read_info.row_end-pos); if (!read_info.enclosed && - (enclosed_length && length == 4 && !memcmp(pos,"NULL",4)) || + (enclosed_length && length == 4 && + !memcmp(pos, STRING_WITH_LEN("NULL"))) || (length == 1 && read_info.found_null)) { if (item->type() == Item::FIELD_ITEM) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2659689a4bc..62365710a54 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3682,7 +3682,8 @@ end_with_restore_list: if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) break; #ifdef HAVE_DLOPEN - if (sp_find_function(thd, lex->spname)) + if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE)) { my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str); goto error; @@ -4033,8 +4034,8 @@ end_with_restore_list: break; } case SQLCOM_SAVEPOINT: - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) || - !opt_using_transactions) + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) || + thd->in_sub_stmt) || !opt_using_transactions) send_ok(thd); else { @@ -4216,7 +4217,8 @@ end_with_restore_list: By this moment all needed SPs should be in cache so no need to look into DB. */ - if (!(sp= sp_find_procedure(thd, lex->spname, TRUE))) + if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", lex->spname->m_qname.str); @@ -4340,9 +4342,11 @@ end_with_restore_list: memcpy(&chistics, &lex->sp_chistics, sizeof(chistics)); if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) - sp= sp_find_procedure(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, FALSE); else - sp= sp_find_function(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE); mysql_reset_errors(thd, 0); if (! sp) { @@ -4418,9 +4422,11 @@ end_with_restore_list: char *db, *name; if (lex->sql_command == SQLCOM_DROP_PROCEDURE) - sp= sp_find_procedure(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, FALSE); else - sp= sp_find_function(thd, lex->spname); + sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE); mysql_reset_errors(thd, 0); if (sp) { @@ -4548,6 +4554,33 @@ end_with_restore_list: lex->wild->ptr() : NullS)); break; } +#ifndef DBUG_OFF + case SQLCOM_SHOW_PROC_CODE: + case SQLCOM_SHOW_FUNC_CODE: + { + sp_head *sp; + + if (lex->spname->m_name.length > NAME_LEN) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str); + goto error; + } + if (lex->sql_command == SQLCOM_SHOW_PROC_CODE) + sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, + &thd->sp_proc_cache, FALSE); + else + sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, + &thd->sp_func_cache, FALSE); + if (!sp || !sp->show_routine_code(thd)) + { + /* We don't distinguish between errors for now */ + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), + SP_COM_STRING(lex), lex->spname->m_name.str); + goto error; + } + break; + } +#endif // ifndef DBUG_OFF case SQLCOM_CREATE_VIEW: { if (end_active_trans(thd)) @@ -4566,7 +4599,7 @@ end_with_restore_list: buff.append(command[thd->lex->create_view_mode].str, command[thd->lex->create_view_mode].length); view_store_options(thd, first_table, &buff); - buff.append("VIEW ", 5); + buff.append(STRING_WITH_LEN("VIEW ")); /* Test if user supplied a db (ie: we did not use thd->db) */ if (first_table->db != thd->db && first_table->db[0]) { @@ -4576,7 +4609,7 @@ end_with_restore_list: } append_identifier(thd, &buff, first_table->table_name, first_table->table_name_length); - buff.append(" AS ", 4); + buff.append(STRING_WITH_LEN(" AS ")); buff.append(first_table->source.str, first_table->source.length); Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index b3e558c94d0..ffbbf0c6476 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1929,7 +1929,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len) variable absent or equal to NULL, so we need to set variable to something reasonable to get a readable error message during parsing */ - str.set("NULL", 4, &my_charset_latin1); + str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1); } needs_conversion= String::needs_conversion(var_value->length(), diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a847c2a57a5..bd23a43a3d5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13690,7 +13690,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, { SELECT_LEX *sl= join->unit->first_select(); uint len= 6, lastop= 0; - memcpy(table_name_buffer, "<union", 6); + memcpy(table_name_buffer, STRING_WITH_LEN("<union")); for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select()) { len+= lastop; @@ -13699,7 +13699,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, } if (sl || len + lastop >= NAME_LEN) { - memcpy(table_name_buffer + len, "...>", 5); + memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1); len+= 4; } else @@ -13878,7 +13878,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) { - extra.append("; Using "); + extra.append(STRING_WITH_LEN("; Using ")); tab->select->quick->add_info_string(&extra); } if (tab->select) @@ -13886,7 +13886,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (tab->use_quick == 2) { char buf[MAX_KEY/8+1]; - extra.append("; Range checked for each record (index map: 0x"); + extra.append(STRING_WITH_LEN("; Range checked for each " + "record (index map: 0x")); extra.append(tab->keys.print(buf)); extra.append(')'); } @@ -13896,38 +13897,39 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (thd->variables.engine_condition_pushdown && pushed_cond) { - extra.append("; Using where with pushed condition"); + extra.append(STRING_WITH_LEN("; Using where with pushed " + "condition")); if (thd->lex->describe & DESCRIBE_EXTENDED) { - extra.append(": "); + extra.append(STRING_WITH_LEN(": ")); ((COND *)pushed_cond)->print(&extra); } } else - extra.append("; Using where"); + extra.append(STRING_WITH_LEN("; Using where")); } } if (key_read) { if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) - extra.append("; Using index for group-by"); + extra.append(STRING_WITH_LEN("; Using index for group-by")); else - extra.append("; Using index"); + extra.append(STRING_WITH_LEN("; Using index")); } if (table->reginfo.not_exists_optimize) - extra.append("; Not exists"); + extra.append(STRING_WITH_LEN("; Not exists")); if (need_tmp_table) { need_tmp_table=0; - extra.append("; Using temporary"); + extra.append(STRING_WITH_LEN("; Using temporary")); } if (need_order) { need_order=0; - extra.append("; Using filesort"); + extra.append(STRING_WITH_LEN("; Using filesort")); } if (distinct & test_all_bits(used_tables,thd->used_tables)) - extra.append("; Distinct"); + extra.append(STRING_WITH_LEN("; Distinct")); /* Skip initial "; "*/ const char *str= extra.ptr(); @@ -14044,15 +14046,18 @@ static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables) { TABLE_LIST *curr= *tbl; if (curr->outer_join) - str->append(" left join ", 11); // MySQL converts right to left joins + { + /* MySQL converts right to left joins */ + str->append(STRING_WITH_LEN(" left join ")); + } else if (curr->straight) - str->append(" straight_join ", 15); + str->append(STRING_WITH_LEN(" straight_join ")); else - str->append(" join ", 6); + str->append(STRING_WITH_LEN(" join ")); curr->print(thd, str); if (curr->on_expr) { - str->append(" on(", 4); + str->append(STRING_WITH_LEN(" on(")); curr->on_expr->print(str); str->append(')'); } @@ -14137,28 +14142,28 @@ void st_select_lex::print(THD *thd, String *str) if (!thd) thd= current_thd; - str->append("select ", 7); + str->append(STRING_WITH_LEN("select ")); /* First add options */ if (options & SELECT_STRAIGHT_JOIN) - str->append("straight_join ", 14); + str->append(STRING_WITH_LEN("straight_join ")); if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) && (this == &thd->lex->select_lex)) - str->append("high_priority ", 14); + str->append(STRING_WITH_LEN("high_priority ")); if (options & SELECT_DISTINCT) - str->append("distinct ", 9); + str->append(STRING_WITH_LEN("distinct ")); if (options & SELECT_SMALL_RESULT) - str->append("sql_small_result ", 17); + str->append(STRING_WITH_LEN("sql_small_result ")); if (options & SELECT_BIG_RESULT) - str->append("sql_big_result ", 15); + str->append(STRING_WITH_LEN("sql_big_result ")); if (options & OPTION_BUFFER_RESULT) - str->append("sql_buffer_result ", 18); + str->append(STRING_WITH_LEN("sql_buffer_result ")); if (options & OPTION_FOUND_ROWS) - str->append("sql_calc_found_rows ", 20); + str->append(STRING_WITH_LEN("sql_calc_found_rows ")); if (!thd->lex->safe_to_cache_query) - str->append("sql_no_cache ", 13); + str->append(STRING_WITH_LEN("sql_no_cache ")); if (options & OPTION_TO_QUERY_CACHE) - str->append("sql_cache ", 10); + str->append(STRING_WITH_LEN("sql_cache ")); //Item List bool first= 1; @@ -14179,7 +14184,7 @@ void st_select_lex::print(THD *thd, String *str) */ if (table_list.elements) { - str->append(" from ", 6); + str->append(STRING_WITH_LEN(" from ")); /* go through join tree */ print_join(thd, str, &top_join_list); } @@ -14190,22 +14195,22 @@ void st_select_lex::print(THD *thd, String *str) cur_where= join->conds; if (cur_where) { - str->append(" where ", 7); + str->append(STRING_WITH_LEN(" where ")); cur_where->print(str); } // group by & olap if (group_list.elements) { - str->append(" group by ", 10); + str->append(STRING_WITH_LEN(" group by ")); print_order(str, (ORDER *) group_list.first); switch (olap) { case CUBE_TYPE: - str->append(" with cube", 10); + str->append(STRING_WITH_LEN(" with cube")); break; case ROLLUP_TYPE: - str->append(" with rollup", 12); + str->append(STRING_WITH_LEN(" with rollup")); break; default: ; //satisfy compiler @@ -14219,13 +14224,13 @@ void st_select_lex::print(THD *thd, String *str) if (cur_having) { - str->append(" having ", 8); + str->append(STRING_WITH_LEN(" having ")); cur_having->print(str); } if (order_list.elements) { - str->append(" order by ", 10); + str->append(STRING_WITH_LEN(" order by ")); print_order(str, (ORDER *) order_list.first); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5ad987d6b7a..9449224c01a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -504,22 +504,22 @@ bool mysqld_show_create_db(THD *thd, char *dbname, protocol->prepare_for_resend(); protocol->store(dbname, strlen(dbname), system_charset_info); buffer.length(0); - buffer.append("CREATE DATABASE ", 16); + buffer.append(STRING_WITH_LEN("CREATE DATABASE ")); if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) - buffer.append("/*!32312 IF NOT EXISTS*/ ", 25); + buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ ")); append_identifier(thd, &buffer, dbname, strlen(dbname)); if (create.default_table_charset) { - buffer.append(" /*!40100", 9); - buffer.append(" DEFAULT CHARACTER SET ", 23); + buffer.append(STRING_WITH_LEN(" /*!40100")); + buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET ")); buffer.append(create.default_table_charset->csname); if (!(create.default_table_charset->state & MY_CS_PRIMARY)) { - buffer.append(" COLLATE ", 9); + buffer.append(STRING_WITH_LEN(" COLLATE ")); buffer.append(create.default_table_charset->name); } - buffer.append(" */", 3); + buffer.append(STRING_WITH_LEN(" */")); } protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); @@ -730,7 +730,7 @@ static void append_directory(THD *thd, String *packet, const char *dir_type, uint length= dirname_length(filename); packet->append(' '); packet->append(dir_type); - packet->append(" DIRECTORY='", 12); + packet->append(STRING_WITH_LEN(" DIRECTORY='")); #ifdef __WIN__ /* Convert \ to / to be able to create table on unix */ char *winfilename= (char*) thd->memdup(filename, length); @@ -779,16 +779,16 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) restore_record(table, s->default_values); // Get empty record if (share->tmp_table) - packet->append("CREATE TEMPORARY TABLE ", 23); + packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE ")); else - packet->append("CREATE TABLE ", 13); + packet->append(STRING_WITH_LEN("CREATE TABLE ")); if (table_list->schema_table) alias= table_list->schema_table->table_name; else alias= (lower_case_table_names == 2 ? table->alias : share->table_name); append_identifier(thd, packet, alias, strlen(alias)); - packet->append(" (\n", 3); + packet->append(STRING_WITH_LEN(" (\n")); for (ptr=table->field ; (field= *ptr); ptr++) { @@ -797,9 +797,9 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) uint flags = field->flags; if (ptr != table->field) - packet->append(",\n", 2); + packet->append(STRING_WITH_LEN(",\n")); - packet->append(" ", 2); + packet->append(STRING_WITH_LEN(" ")); append_identifier(thd,packet,field->field_name, strlen(field->field_name)); packet->append(' '); // check for surprises from the previous call to Field::sql_type() @@ -816,7 +816,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) { if (field->charset() != share->table_charset) { - packet->append(" character set ", 15); + packet->append(STRING_WITH_LEN(" character set ")); packet->append(field->charset()->csname); } /* @@ -825,20 +825,20 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) */ if (!(field->charset()->state & MY_CS_PRIMARY)) { - packet->append(" collate ", 9); + packet->append(STRING_WITH_LEN(" collate ")); packet->append(field->charset()->name); } } if (flags & NOT_NULL_FLAG) - packet->append(" NOT NULL", 9); + packet->append(STRING_WITH_LEN(" NOT NULL")); else if (field->type() == FIELD_TYPE_TIMESTAMP) { /* TIMESTAMP field require explicit NULL flag, because unlike all other fields they are treated as NOT NULL by default. */ - packet->append(" NULL", 5); + packet->append(STRING_WITH_LEN(" NULL")); } /* @@ -856,9 +856,9 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (has_default) { - packet->append(" default ", 9); + packet->append(STRING_WITH_LEN(" default ")); if (has_now_default) - packet->append("CURRENT_TIMESTAMP",17); + packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP")); else if (!field->is_null()) { // Not null by default type.set(tmp, sizeof(tmp), field->charset()); @@ -873,10 +873,10 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) append_unescaped(packet, def_val.ptr(), def_val.length()); } else - packet->append("''",2); + packet->append(STRING_WITH_LEN("''")); } else if (field->maybe_null()) - packet->append("NULL", 4); // Null as default + packet->append(STRING_WITH_LEN("NULL")); // Null as default else packet->append(tmp); } @@ -884,15 +884,15 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (!(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS) && table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) - packet->append(" on update CURRENT_TIMESTAMP",28); + packet->append(STRING_WITH_LEN(" on update CURRENT_TIMESTAMP")); if (field->unireg_check == Field::NEXT_NUMBER && !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) - packet->append(" auto_increment", 15 ); + packet->append(STRING_WITH_LEN(" auto_increment")); if (field->comment.length) { - packet->append(" COMMENT ",9); + packet->append(STRING_WITH_LEN(" COMMENT ")); append_unescaped(packet, field->comment.str, field->comment.length); } } @@ -907,20 +907,20 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) { KEY_PART_INFO *key_part= key_info->key_part; bool found_primary=0; - packet->append(",\n ", 4); + packet->append(STRING_WITH_LEN(",\n ")); if (i == primary_key && !strcmp(key_info->name, primary_key_name)) { found_primary=1; - packet->append("PRIMARY ", 8); + packet->append(STRING_WITH_LEN("PRIMARY ")); } else if (key_info->flags & HA_NOSAME) - packet->append("UNIQUE ", 7); + packet->append(STRING_WITH_LEN("UNIQUE ")); else if (key_info->flags & HA_FULLTEXT) - packet->append("FULLTEXT ", 9); + packet->append(STRING_WITH_LEN("FULLTEXT ")); else if (key_info->flags & HA_SPATIAL) - packet->append("SPATIAL ", 8); - packet->append("KEY ", 4); + packet->append(STRING_WITH_LEN("SPATIAL ")); + packet->append(STRING_WITH_LEN("KEY ")); if (!found_primary) append_identifier(thd, packet, key_info->name, strlen(key_info->name)); @@ -929,19 +929,19 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) !limited_mysql_mode && !foreign_db_mode) { if (key_info->algorithm == HA_KEY_ALG_BTREE) - packet->append(" USING BTREE", 12); + packet->append(STRING_WITH_LEN(" USING BTREE")); if (key_info->algorithm == HA_KEY_ALG_HASH) - packet->append(" USING HASH", 11); + packet->append(STRING_WITH_LEN(" USING HASH")); // +BAR: send USING only in non-default case: non-spatial rtree if ((key_info->algorithm == HA_KEY_ALG_RTREE) && !(key_info->flags & HA_SPATIAL)) - packet->append(" USING RTREE", 12); + packet->append(STRING_WITH_LEN(" USING RTREE")); // No need to send USING FULLTEXT, it is sent as FULLTEXT KEY } - packet->append(" (", 2); + packet->append(STRING_WITH_LEN(" (")); for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { @@ -978,71 +978,71 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) file->free_foreign_key_create_info(for_str); } - packet->append("\n)", 2); + packet->append(STRING_WITH_LEN("\n)")); if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) { if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) - packet->append(" TYPE=", 6); + packet->append(STRING_WITH_LEN(" TYPE=")); else - packet->append(" ENGINE=", 8); + packet->append(STRING_WITH_LEN(" ENGINE=")); packet->append(file->table_type()); if (share->table_charset && !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) { - packet->append(" DEFAULT CHARSET=", 17); + packet->append(STRING_WITH_LEN(" DEFAULT CHARSET=")); packet->append(share->table_charset->csname); if (!(share->table_charset->state & MY_CS_PRIMARY)) { - packet->append(" COLLATE=", 9); + packet->append(STRING_WITH_LEN(" COLLATE=")); packet->append(table->s->table_charset->name); } } if (share->min_rows) { - packet->append(" MIN_ROWS=", 10); + packet->append(STRING_WITH_LEN(" MIN_ROWS=")); end= longlong10_to_str(share->min_rows, buff, 10); packet->append(buff, (uint) (end- buff)); } if (share->max_rows && !table_list->schema_table) { - packet->append(" MAX_ROWS=", 10); + packet->append(STRING_WITH_LEN(" MAX_ROWS=")); end= longlong10_to_str(share->max_rows, buff, 10); packet->append(buff, (uint) (end - buff)); } if (share->avg_row_length) { - packet->append(" AVG_ROW_LENGTH=", 16); + packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH=")); end= longlong10_to_str(share->avg_row_length, buff,10); packet->append(buff, (uint) (end - buff)); } if (share->db_create_options & HA_OPTION_PACK_KEYS) - packet->append(" PACK_KEYS=1", 12); + packet->append(STRING_WITH_LEN(" PACK_KEYS=1")); if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) - packet->append(" PACK_KEYS=0", 12); + packet->append(STRING_WITH_LEN(" PACK_KEYS=0")); if (share->db_create_options & HA_OPTION_CHECKSUM) - packet->append(" CHECKSUM=1", 11); + packet->append(STRING_WITH_LEN(" CHECKSUM=1")); if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) - packet->append(" DELAY_KEY_WRITE=1",18); + packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1")); if (share->row_type != ROW_TYPE_DEFAULT) { - packet->append(" ROW_FORMAT=",12); + packet->append(STRING_WITH_LEN(" ROW_FORMAT=")); packet->append(ha_row_type[(uint) share->row_type]); } table->file->append_create_info(packet); if (share->comment && share->comment[0]) { - packet->append(" COMMENT=", 9); + packet->append(STRING_WITH_LEN(" COMMENT=")); append_unescaped(packet, share->comment, strlen(share->comment)); } if (share->connect_string.length) { - packet->append(" CONNECTION=", 12); + packet->append(STRING_WITH_LEN(" CONNECTION=")); append_unescaped(packet, share->connect_string.str, share->connect_string.length); } if (file->raid_type) @@ -1063,25 +1063,25 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) void view_store_options(THD *thd, TABLE_LIST *table, String *buff) { - buff->append("ALGORITHM=", 10); + buff->append(STRING_WITH_LEN("ALGORITHM=")); switch ((int8)table->algorithm) { case VIEW_ALGORITHM_UNDEFINED: - buff->append("UNDEFINED ", 10); + buff->append(STRING_WITH_LEN("UNDEFINED ")); break; case VIEW_ALGORITHM_TMPTABLE: - buff->append("TEMPTABLE ", 10); + buff->append(STRING_WITH_LEN("TEMPTABLE ")); break; case VIEW_ALGORITHM_MERGE: - buff->append("MERGE ", 6); + buff->append(STRING_WITH_LEN("MERGE ")); break; default: DBUG_ASSERT(0); // never should happen } append_definer(thd, buff, &table->definer.user, &table->definer.host); if (table->view_suid) - buff->append("SQL SECURITY DEFINER ", 21); + buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER ")); else - buff->append("SQL SECURITY INVOKER ", 21); + buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER ")); } @@ -1139,19 +1139,19 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) } } - buff->append("CREATE ", 7); + buff->append(STRING_WITH_LEN("CREATE ")); if (!foreign_db_mode) { view_store_options(thd, table, buff); } - buff->append("VIEW ", 5); + buff->append(STRING_WITH_LEN("VIEW ")); if (!table->compact_view_format) { append_identifier(thd, buff, table->view_db.str, table->view_db.length); buff->append('.'); } append_identifier(thd, buff, table->view_name.str, table->view_name.length); - buff->append(" AS ", 4); + buff->append(STRING_WITH_LEN(" AS ")); /* We can't just use table->query, because our SQL_MODE may trigger @@ -1162,9 +1162,9 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) if (table->with_check != VIEW_CHECK_NONE) { if (table->with_check == VIEW_CHECK_LOCAL) - buff->append(" WITH LOCAL CHECK OPTION", 24); + buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION")); else - buff->append(" WITH CASCADED CHECK OPTION", 27); + buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION")); } return 0; } @@ -1426,7 +1426,7 @@ static bool show_status_array(THD *thd, const char *wild, case SHOW_SLAVE_RUNNING: { pthread_mutex_lock(&LOCK_active_mi); - end= strmov(buff, (active_mi->slave_running && + end= strmov(buff, (active_mi && active_mi->slave_running && active_mi->rli.slave_running) ? "ON" : "OFF"); pthread_mutex_unlock(&LOCK_active_mi); break; @@ -1437,12 +1437,15 @@ static bool show_status_array(THD *thd, const char *wild, TODO: in 5.1 with multimaster, have one such counter per line in SHOW SLAVE STATUS, and have the sum over all lines here. */ - pthread_mutex_lock(&LOCK_active_mi); - pthread_mutex_lock(&active_mi->rli.data_lock); - end= int10_to_str(active_mi->rli.retried_trans, buff, 10); - pthread_mutex_unlock(&active_mi->rli.data_lock); - pthread_mutex_unlock(&LOCK_active_mi); - break; + pthread_mutex_lock(&LOCK_active_mi); + if (active_mi) + { + pthread_mutex_lock(&active_mi->rli.data_lock); + end= int10_to_str(active_mi->rli.retried_trans, buff, 10); + pthread_mutex_unlock(&active_mi->rli.data_lock); + } + pthread_mutex_unlock(&LOCK_active_mi); + break; } case SHOW_SLAVE_SKIP_ERRORS: { @@ -2148,20 +2151,24 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { if (with_i_schema) { - table->field[3]->store("SYSTEM VIEW", 11, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), + system_charset_info); } else { my_snprintf(end, len, "/%s%s", file_name, reg_ext); switch (mysql_frm_type(thd, path, ¬_used)) { case FRMTYPE_ERROR: - table->field[3]->store("ERROR", 5, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("ERROR"), + system_charset_info); break; case FRMTYPE_TABLE: - table->field[3]->store("BASE TABLE", 10, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), + system_charset_info); break; case FRMTYPE_VIEW: - table->field[3]->store("VIEW", 4, system_charset_info); + table->field[3]->store(STRING_WITH_LEN("VIEW"), + system_charset_info); break; default: DBUG_ASSERT(0); @@ -2314,8 +2321,8 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, } else if (tables->view) { - table->field[3]->store("VIEW", 4, cs); - table->field[20]->store("VIEW", 4, cs); + table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); + table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); } else { @@ -2326,11 +2333,11 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO | HA_STATUS_NO_LOCK); if (share->tmp_table == SYSTEM_TMP_TABLE) - table->field[3]->store("SYSTEM VIEW", 11, cs); + table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else if (share->tmp_table) - table->field[3]->store("LOCAL TEMPORARY", 15, cs); + table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs); else - table->field[3]->store("BASE TABLE", 10, cs); + table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); for (int i= 4; i < 20; i++) { @@ -2566,7 +2573,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, if (show_table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_UN_FIELD) { - table->field[5]->store("CURRENT_TIMESTAMP", 17, cs); + table->field[5]->store(STRING_WITH_LEN("CURRENT_TIMESTAMP"), cs); table->field[5]->set_notnull(); } else if (field->unireg_check != Field::NEXT_NUMBER && @@ -2828,8 +2835,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, get_field(thd->mem_root, proc_table->field[10], &tmp_string); table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs); } - table->field[6]->store("SQL", 3, cs); - table->field[10]->store("SQL", 3, cs); + table->field[6]->store(STRING_WITH_LEN("SQL"), cs); + table->field[10]->store(STRING_WITH_LEN("SQL"), cs); get_field(thd->mem_root, proc_table->field[6], &tmp_string); table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); table->field[12]->store(sp_data_access_name[enum_idx].str, @@ -2984,7 +2991,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, pos= show_table->file->index_type(i); table->field[13]->store(pos, strlen(pos), cs); if (!show_table->s->keys_in_use.is_set(i)) - table->field[14]->store("disabled", 8, cs); + table->field[14]->store(STRING_WITH_LEN("disabled"), cs); else table->field[14]->store("", 0, cs); table->field[14]->set_notnull(); @@ -3094,13 +3101,15 @@ static int get_schema_constraints_record(THD *thd, struct st_table_list *tables, if (i == primary_key && !strcmp(key_info->name, primary_key_name)) { if (store_constraints(thd, table, base_name, file_name, key_info->name, - strlen(key_info->name), "PRIMARY KEY", 11)) + strlen(key_info->name), + STRING_WITH_LEN("PRIMARY KEY"))) DBUG_RETURN(1); } else if (key_info->flags & HA_NOSAME) { if (store_constraints(thd, table, base_name, file_name, key_info->name, - strlen(key_info->name), "UNIQUE", 6)) + strlen(key_info->name), + STRING_WITH_LEN("UNIQUE"))) DBUG_RETURN(1); } } @@ -3141,11 +3150,11 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db, table->field[5]->store(db, strlen(db), cs); table->field[6]->store(tname, strlen(tname), cs); table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs); - table->field[10]->store("ROW", 3, cs); + table->field[10]->store(STRING_WITH_LEN("ROW"), cs); table->field[11]->store(trg_action_time_type_names[timing].str, trg_action_time_type_names[timing].length, cs); - table->field[14]->store("OLD", 3, cs); - table->field[15]->store("NEW", 3, cs); + table->field[14]->store(STRING_WITH_LEN("OLD"), cs); + table->field[15]->store(STRING_WITH_LEN("NEW"), cs); sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, @@ -3536,9 +3545,9 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(field_info->old_name); if (lex->wild && lex->wild->ptr()) { - buffer.append(" ("); + buffer.append(STRING_WITH_LEN(" (")); buffer.append(lex->wild->ptr()); - buffer.append(")"); + buffer.append(')'); } field->set_name(buffer.ptr(), buffer.length(), system_charset_info); } @@ -3559,9 +3568,9 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(lex->select_lex.db); if (lex->wild && lex->wild->ptr()) { - buffer.append(" ("); + buffer.append(STRING_WITH_LEN(" (")); buffer.append(lex->wild->ptr()); - buffer.append(")"); + buffer.append(')'); } Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 51f802e7465..fd7bca7ec21 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -848,22 +848,22 @@ void String::print(String *str) switch (c) { case '\\': - str->append("\\\\", 2); + str->append(STRING_WITH_LEN("\\\\")); break; case '\0': - str->append("\\0", 2); + str->append(STRING_WITH_LEN("\\0")); break; case '\'': - str->append("\\'", 2); + str->append(STRING_WITH_LEN("\\'")); break; case '\n': - str->append("\\n", 2); + str->append(STRING_WITH_LEN("\\n")); break; case '\r': - str->append("\\r", 2); + str->append(STRING_WITH_LEN("\\r")); break; case 26: //Ctrl-Z - str->append("\\z", 2); + str->append(STRING_WITH_LEN("\\z")); break; default: str->append(c); diff --git a/sql/sql_string.h b/sql/sql_string.h index ddae6368228..67c3e0c62f2 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -24,6 +24,8 @@ #define NOT_FIXED_DEC 31 #endif +#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1) + class String; int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 815cdfe6cc5..e8ffdc23ec5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -705,7 +705,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, MY_CS_BINSORT,MYF(0)))) { char tmp[64]; - strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), "_bin", 4); + strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), + STRING_WITH_LEN("_bin")); my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); DBUG_RETURN(-1); } @@ -1951,7 +1952,7 @@ static int send_check_errmsg(THD *thd, TABLE_LIST* table, protocol->prepare_for_resend(); protocol->store(table->alias, system_charset_info); protocol->store((char*) operator_name, system_charset_info); - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(errmsg, system_charset_info); thd->clear_error(); if (protocol->write()) @@ -2242,7 +2243,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); - protocol->store("error",5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); if (!(err_msg=thd->net.last_error)) err_msg=ER(ER_CHECK_NO_SUCH_TABLE); /* if it was a view will check md5 sum */ @@ -2279,7 +2280,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY), table_name); protocol->store(buff, length, system_charset_info); @@ -2314,8 +2315,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); - protocol->store("warning", 7, system_charset_info); - protocol->store("Table is marked as crashed", 26, system_charset_info); + protocol->store(STRING_WITH_LEN("warning"), system_charset_info); + protocol->store(STRING_WITH_LEN("Table is marked as crashed"), + system_charset_info); if (protocol->write()) goto err; } @@ -2339,7 +2341,7 @@ send_result_message: char buf[ERRMSGSIZE+20]; uint length=my_snprintf(buf, ERRMSGSIZE, ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); - protocol->store("note", 4, system_charset_info); + protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(buf, length, system_charset_info); } break; @@ -2349,41 +2351,45 @@ send_result_message: char buf[ERRMSGSIZE+20]; uint length= my_snprintf(buf, ERRMSGSIZE, ER(ER_BAD_TABLE_ERROR), table_name); - protocol->store("note", 4, system_charset_info); + protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(buf, length, system_charset_info); } break; case HA_ADMIN_OK: - protocol->store("status", 6, system_charset_info); - protocol->store("OK",2, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("OK"), system_charset_info); break; case HA_ADMIN_FAILED: - protocol->store("status", 6, system_charset_info); - protocol->store("Operation failed",16, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("Operation failed"), + system_charset_info); break; case HA_ADMIN_REJECT: - protocol->store("status", 6, system_charset_info); - protocol->store("Operation need committed state",30, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("Operation need committed state"), + system_charset_info); open_for_modify= FALSE; break; case HA_ADMIN_ALREADY_DONE: - protocol->store("status", 6, system_charset_info); - protocol->store("Table is already up to date", 27, system_charset_info); + protocol->store(STRING_WITH_LEN("status"), system_charset_info); + protocol->store(STRING_WITH_LEN("Table is already up to date"), + system_charset_info); break; case HA_ADMIN_CORRUPT: - protocol->store("error", 5, system_charset_info); - protocol->store("Corrupt", 7, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); + protocol->store(STRING_WITH_LEN("Corrupt"), system_charset_info); fatal_error=1; break; case HA_ADMIN_INVALID: - protocol->store("error", 5, system_charset_info); - protocol->store("Invalid argument",16, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); + protocol->store(STRING_WITH_LEN("Invalid argument"), + system_charset_info); break; case HA_ADMIN_TRY_ALTER: @@ -2419,7 +2425,7 @@ send_result_message: else { /* Hijack the row already in-progress. */ - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(err_msg, system_charset_info); (void)protocol->write(); /* Start off another row for HA_ADMIN_FAILED */ @@ -2436,7 +2442,7 @@ send_result_message: } case HA_ADMIN_WRONG_CHECKSUM: { - protocol->store("note", 4, system_charset_info); + protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)), system_charset_info); break; @@ -2448,7 +2454,7 @@ send_result_message: uint length=my_snprintf(buf, ERRMSGSIZE, "Unknown - internal error %d during operation", result_code); - protocol->store("error", 5, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(buf, length, system_charset_info); fatal_error=1; break; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 84cc79ee4dc..296b55679a3 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -20,7 +20,8 @@ #include "sql_trigger.h" #include "parse_file.h" -static const LEX_STRING triggers_file_type= {(char *)"TRIGGERS", 8}; +static const LEX_STRING triggers_file_type= + {STRING_WITH_LEN("TRIGGERS")}; const char * const triggers_file_ext= ".TRG"; @@ -33,21 +34,17 @@ const char * const triggers_file_ext= ".TRG"; static File_option triggers_file_parameters[]= { { - { (char *) STRING_WITH_LEN("triggers") }, + {STRING_WITH_LEN("triggers") }, offsetof(class Table_triggers_list, definitions_list), FILE_OPTIONS_STRLIST }, { - /* - FIXME: Length specified for "sql_modes" key is erroneous, problem caused - by this are reported as BUG#14090 and should be fixed ASAP. - */ - { (char *) "sql_modes", 13 }, + {STRING_WITH_LEN("sql_modes") }, offsetof(class Table_triggers_list, definition_modes_list), FILE_OPTIONS_ULLLIST }, { - { (char *) STRING_WITH_LEN("definers") }, + {STRING_WITH_LEN("definers") }, offsetof(class Table_triggers_list, definers_list), FILE_OPTIONS_STRLIST }, @@ -73,7 +70,8 @@ struct st_trigname LEX_STRING trigger_table; }; -static const LEX_STRING trigname_file_type= {(char *)"TRIGGERNAME", 11}; +static const LEX_STRING trigname_file_type= + {STRING_WITH_LEN("TRIGGERNAME")}; const char * const trigname_file_ext= ".TRN"; @@ -84,7 +82,7 @@ static File_option trigname_file_parameters[]= FIXME: Length specified for "trigger_table" key is erroneous, problem caused by this are reported as BUG#14090 and should be fixed ASAP. */ - { (char *) "trigger_table", 15 }, + {STRING_WITH_LEN("trigger_table")}, offsetof(struct st_trigname, trigger_table), FILE_OPTIONS_ESTRING }, @@ -108,6 +106,21 @@ const LEX_STRING trg_event_type_names[]= static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig); +bool handle_old_incorrect_sql_modes(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, + char *end, gptr hook_data); + +class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook +{ +private: + char *path; +public: + Handle_old_incorrect_sql_modes_hook(char *file_path) + :path(file_path) + {}; + virtual bool process_unknown_string(char *&unknown_key, gptr base, + MEM_ROOT *mem_root, char *end); +}; /* Create or drop trigger for table. @@ -237,7 +250,7 @@ end: { log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */ - log_query.append("CREATE "); + log_query.append(STRING_WITH_LEN("CREATE ")); append_definer(thd, &log_query, &definer_user, &definer_host); log_query.append(thd->lex->trigger_definition_begin); } @@ -691,6 +704,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, { Table_triggers_list *triggers= new (&table->mem_root) Table_triggers_list(table); + Handle_old_incorrect_sql_modes_hook sql_modes_hook(path.str); if (!triggers) DBUG_RETURN(1); @@ -705,7 +719,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, triggers->definers_list.empty(); if (parser->parse((gptr)triggers, &table->mem_root, - triggers_file_parameters, TRG_NUM_REQUIRED_PARAMETERS)) + triggers_file_parameters, + TRG_NUM_REQUIRED_PARAMETERS, + &sql_modes_hook)) DBUG_RETURN(1); List_iterator_fast<LEX_STRING> it(triggers->definitions_list); @@ -800,6 +816,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, List_iterator_fast<LEX_STRING> it_definer(triggers-> definers_list); LEX *old_lex= thd->lex, lex; + sp_rcontext *save_spcont= thd->spcont; ulong save_sql_mode= thd->variables.sql_mode; thd->lex= &lex; @@ -815,6 +832,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->variables.sql_mode= (ulong)*trg_sql_mode; lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length); + thd->spcont= 0; if (yyparse((void *)thd) || thd->is_fatal_error) { /* @@ -895,6 +913,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->db= save_db.str; thd->db_length= save_db.length; thd->lex= old_lex; + thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; DBUG_RETURN(0); @@ -903,6 +922,7 @@ err_with_lex_cleanup: // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; + thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; thd->db= save_db.str; thd->db_length= save_db.length; @@ -1020,7 +1040,8 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) } if (parser->parse((gptr)&trigname, thd->mem_root, - trigname_file_parameters, 1)) + trigname_file_parameters, 1, + &file_parser_dummy_hook)) DBUG_RETURN(0); /* We need to reset statement table list to be PS/SP friendly. */ @@ -1172,3 +1193,65 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, return res; } + + +/* + Trigger BUG#14090 compatibility hook + + SYNOPSIS + Handle_old_incorrect_sql_modes_hook::process_unknown_string() + unknown_key [in/out] reference on the line with unknown + parameter and the parsing point + base [in] base address for parameter writing (structure + like TABLE) + mem_root [in] MEM_ROOT for parameters allocation + end [in] the end of the configuration + + NOTE: this hook process back compatibility for incorrectly written + sql_modes parameter (see BUG#14090). + + RETURN + FALSE OK + TRUE Error +*/ + +bool +Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, + gptr base, + MEM_ROOT *mem_root, + char *end) +{ +#define INVALID_SQL_MODES_LENGTH 13 + DBUG_ENTER("handle_old_incorrect_sql_modes"); + DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end && + unknown_key[INVALID_SQL_MODES_LENGTH] == '=' && + !memcmp(unknown_key, STRING_WITH_LEN("sql_modes"))) + { + DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected")); + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_OLD_FILE_FORMAT, + ER(ER_OLD_FILE_FORMAT), + (char *)path, "TRIGGER"); + File_option sql_modes_parameters= + { + {STRING_WITH_LEN("sql_modes") }, + offsetof(class Table_triggers_list, definition_modes_list), + FILE_OPTIONS_ULLLIST + }; + char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1; + if (get_file_options_ulllist(ptr, end, unknown_key, base, + &sql_modes_parameters, mem_root)) + { + DBUG_RETURN(TRUE); + } + /* + Set parsing pointer to the last symbol of string (\n) + 1) to avoid problem with \0 in the junk after sql_modes + 2) to speed up skipping this line by parser. + */ + unknown_key= ptr-1; + } + DBUG_RETURN(FALSE); +} diff --git a/sql/sql_view.cc b/sql/sql_view.cc index b642d24b30d..e03d3b22b89 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -495,7 +495,7 @@ static const int num_view_backups= 3; static File_option view_parameters[]= {{{(char*) STRING_WITH_LEN("query")}, offsetof(TABLE_LIST, query), - FILE_OPTIONS_STRING}, + FILE_OPTIONS_ESTRING}, {{(char*) STRING_WITH_LEN("md5")}, offsetof(TABLE_LIST, md5), FILE_OPTIONS_STRING}, @@ -623,7 +623,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, TODO: special cascade/restrict procedure for alter? */ if (parser->parse((gptr)view, thd->mem_root, - view_parameters + revision_number_position, 1)) + view_parameters + revision_number_position, 1, + &file_parser_dummy_hook)) { DBUG_RETURN(thd->net.report_error? -1 : 0); } @@ -792,7 +793,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) be used here */ if (parser->parse((gptr)table, thd->mem_root, view_parameters, - required_view_parameters)) + required_view_parameters, &file_parser_dummy_hook)) goto err; /* @@ -1502,7 +1503,8 @@ mysql_rename_view(THD *thd, /* get view definition and source */ if (parser->parse((gptr)&view_def, thd->mem_root, view_parameters, - array_elements(view_parameters)-1)) + array_elements(view_parameters)-1, + &file_parser_dummy_hook)) goto err; /* rename view and it's backups */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 85c07e6daba..97e97776d36 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -175,6 +175,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CLIENT_SYM %token CLOSE_SYM %token COALESCE +%token CODE_SYM %token COLLATE_SYM %token COLLATION_SYM %token COLUMNS @@ -1604,13 +1605,14 @@ sp_decl: for (uint i = max-$2 ; i < max ; i++) { sp_instr_set *in; + uint off= ctx->pvar_context2index(i); - ctx->set_type(i, type); + ctx->set_type(off, type); if (! has_default) it= new Item_null(); /* QQ Set to the type with null_value? */ in = new sp_instr_set(lex->sphead->instructions(), ctx, - ctx->pvar_context2index(i), + off, it, type, lex, (i == max - 1)); @@ -1619,7 +1621,7 @@ sp_decl: freeing LEX. */ lex->sphead->add_instr(in); - ctx->set_default(i, it); + ctx->set_default(off, it); } lex->sphead->restore_lex(YYTHD); $$.vars= $2; @@ -1693,7 +1695,8 @@ sp_decl: delete $5; YYABORT; } - i= new sp_instr_cpush(sp->instructions(), ctx, $5); + i= new sp_instr_cpush(sp->instructions(), ctx, $5, + ctx->current_cursors()); sp->add_instr(i); ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; @@ -2283,8 +2286,12 @@ sp_case: ivar.str= (char *)"_tmp_"; ivar.length= 5; - Item *var= (Item*) new Item_splocal(ivar, - ctx->current_pvars()-1); + Item_splocal *var= new Item_splocal(ivar, + ctx->current_pvars()-1); +#ifndef DEBUG_OFF + if (var) + var->owner= sp; +#endif Item *expr= new Item_func_eq(var, $2); i= new sp_instr_jump_if_not(ip, ctx, expr, lex); @@ -5865,7 +5872,13 @@ select_var_ident: YYABORT; else { - ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset,t->type)); + my_var *var; + ((select_dumpvar *)lex->result)-> + var_list.push_back(var= new my_var($1,1,t->offset,t->type)); +#ifndef DEBUG_OFF + if (var) + var->owner= lex->sphead; +#endif } } ; @@ -6587,7 +6600,28 @@ show_param: YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) YYABORT; - }; + } + | PROCEDURE CODE_SYM sp_name + { +#ifdef DBUG_OFF + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#else + Lex->sql_command= SQLCOM_SHOW_PROC_CODE; + Lex->spname= $3; +#endif + } + | FUNCTION_SYM CODE_SYM sp_name + { +#ifdef DBUG_OFF + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#else + Lex->sql_command= SQLCOM_SHOW_FUNC_CODE; + Lex->spname= $3; +#endif + } + ; show_engine_param: STATUS_SYM @@ -7147,6 +7181,10 @@ simple_ident: Item_splocal *splocal; splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev - lex->sphead->m_tmp_query); +#ifndef DEBUG_OFF + if (splocal) + splocal->owner= lex->sphead; +#endif $$ = (Item*) splocal; lex->variables_used= 1; lex->safe_to_cache_query=0; @@ -7496,6 +7534,7 @@ keyword_sp: | CHANGED {} | CIPHER_SYM {} | CLIENT_SYM {} + | CODE_SYM {} | COLLATION_SYM {} | COLUMNS {} | COMMITTED_SYM {} @@ -7925,6 +7964,9 @@ option_value: names.length= 5; if (spc && spc->find_pvar(&names)) my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); + else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; } | NAMES_SYM charset_name_or_default opt_collate diff --git a/sql/structs.h b/sql/structs.h index 3c651c491d3..9421ebdc2af 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,8 +20,6 @@ struct st_table; class Field; -#define STRING_WITH_LEN(X) ((char*) X), (sizeof(X)-1) - typedef struct st_lex_string { char *str; diff --git a/sql/table.cc b/sql/table.cc index 3bc5c9a242b..8068a839052 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -110,7 +110,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err; - if (memcmp(head, "TYPE=", 5) == 0) + if (memcmp(head, STRING_WITH_LEN("TYPE=")) == 0) { // new .frm my_close(file,MYF(MY_WME)); diff --git a/sql/tztime.cc b/sql/tztime.cc index 537050e94db..1d06d4d0b8e 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1558,7 +1558,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) sql_print_error("Fatal error: OOM while initializing time zones"); goto end_with_cleanup; } - tmp_tzname->name.set("SYSTEM", 6, &my_charset_latin1); + tmp_tzname->name.set(STRING_WITH_LEN("SYSTEM"), &my_charset_latin1); tmp_tzname->tz= my_tz_SYSTEM; if (my_hash_insert(&tz_names, (const byte *)tmp_tzname)) { |