summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc21
-rw-r--r--sql/ha_myisam.cc10
-rw-r--r--sql/ha_myisammrg.cc2
-rw-r--r--sql/ha_ndbcluster.cc14
-rw-r--r--sql/ha_ndbcluster_binlog.cc13
-rw-r--r--sql/ha_ndbcluster_binlog.h2
-rw-r--r--sql/item.cc21
-rw-r--r--sql/item_func.cc108
-rw-r--r--sql/item_func.h9
-rw-r--r--sql/item_strfunc.cc10
-rw-r--r--sql/item_strfunc.h2
-rw-r--r--sql/item_subselect.cc1
-rw-r--r--sql/item_sum.cc7
-rw-r--r--sql/item_sum.h2
-rw-r--r--sql/item_timefunc.cc15
-rw-r--r--sql/mysql_priv.h23
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sp.cc17
-rw-r--r--sql/sp_head.cc247
-rw-r--r--sql/sp_head.h14
-rw-r--r--sql/sql_acl.cc2
-rw-r--r--sql/sql_base.cc50
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_db.cc110
-rw-r--r--sql/sql_delete.cc9
-rw-r--r--sql/sql_insert.cc8
-rw-r--r--sql/sql_lex.cc25
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc18
-rw-r--r--sql/sql_partition.cc26
-rw-r--r--sql/sql_prepare.cc36
-rw-r--r--sql/sql_rename.cc8
-rw-r--r--sql/sql_show.cc126
-rw-r--r--sql/sql_table.cc296
-rw-r--r--sql/sql_trigger.cc27
-rw-r--r--sql/sql_udf.cc2
-rw-r--r--sql/sql_view.cc25
-rw-r--r--sql/sql_view.h3
-rw-r--r--sql/sql_yacc.yy48
-rw-r--r--sql/table.cc31
-rw-r--r--sql/table.h4
-rw-r--r--sql/udf_example.c2
-rw-r--r--sql/unireg.h3
45 files changed, 993 insertions, 417 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 4e3c54fbd63..6a205db0d80 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -8523,7 +8523,8 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
comment= *fld_comment;
/*
- Set flag if this field doesn't have a default value
+ Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and
+ it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
*/
if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
(fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
@@ -8600,12 +8601,28 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
/* Allow empty as default value. */
String str,*res;
res= fld_default_value->val_str(&str);
- if (res->length())
+ /*
+ A default other than '' is always an error, and any non-NULL
+ specified default is an error in strict mode.
+ */
+ if (res->length() || (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)))
{
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
fld_name); /* purecov: inspected */
DBUG_RETURN(TRUE);
}
+ else
+ {
+ /*
+ Otherwise a default of '' is just a warning.
+ */
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_BLOB_CANT_HAVE_DEFAULT,
+ ER(ER_BLOB_CANT_HAVE_DEFAULT),
+ fld_name);
+ }
def= 0;
}
flags|= BLOB_FLAG;
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 565010a1889..cbb8a7a48c0 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -473,11 +473,14 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
HA_CHECK_OPT tmp_check_opt;
char *backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- const char *table_name= table->s->table_name.str;
+ char table_name[FN_REFLEN];
int error;
const char* errmsg;
DBUG_ENTER("restore");
+ VOID(tablename_to_filename(table->s->table_name.str, table_name,
+ sizeof(table_name)));
+
if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
MI_NAME_DEXT))
DBUG_RETURN(HA_ADMIN_INVALID);
@@ -513,11 +516,14 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
char *backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- const char *table_name= table->s->table_name.str;
+ char table_name[FN_REFLEN];
int error;
const char *errmsg;
DBUG_ENTER("ha_myisam::backup");
+ VOID(tablename_to_filename(table->s->table_name.str, table_name,
+ sizeof(table_name)));
+
if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
reg_ext))
{
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index a15787fdcf0..3ae5406824c 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -477,7 +477,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
an embedded server without changing the paths in the .MRG file.
*/
uint length= build_table_filename(buff, sizeof(buff),
- tables->db, tables->table_name, "");
+ tables->db, tables->table_name, "", 0);
/*
If a MyISAM table is in the same directory as the MERGE table,
we use the table name without a path. This means that the
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 64f0cc0b76e..9b44573673d 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -5801,7 +5801,7 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
DBUG_RETURN(HA_ERR_NO_CONNECTION);
ndb->setDatabaseName(db);
NDBDICT* dict= ndb->getDictionary();
- build_table_filename(key, sizeof(key), db, name, "");
+ build_table_filename(key, sizeof(key), db, name, "", 0);
NDB_SHARE *share= get_share(key, 0, false);
if (share && get_ndb_share_state(share) == NSS_ALTERED)
{
@@ -5944,7 +5944,7 @@ int ndbcluster_drop_database_impl(const char *path)
// Drop any tables belonging to database
char full_path[FN_REFLEN];
char *tmp= full_path +
- build_table_filename(full_path, sizeof(full_path), dbname, "", "");
+ build_table_filename(full_path, sizeof(full_path), dbname, "", "", 0);
ndb->setDatabaseName(dbname);
List_iterator_fast<char> it(drop_list);
@@ -6067,7 +6067,7 @@ int ndbcluster_find_all_files(THD *thd)
/* check if database exists */
char *end= key +
- build_table_filename(key, sizeof(key), elmt.database, "", "");
+ build_table_filename(key, sizeof(key), elmt.database, "", "", 0);
if (my_access(key, F_OK))
{
/* no such database defined, skip table */
@@ -6210,7 +6210,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
}
// File is not in NDB, check for .ndb file with this name
- build_table_filename(name, sizeof(name), db, file_name, ha_ndb_ext);
+ build_table_filename(name, sizeof(name), db, file_name, ha_ndb_ext, 0);
DBUG_PRINT("info", ("Check access for %s", name));
if (my_access(name, F_OK))
{
@@ -6235,7 +6235,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
/* setup logging to binlog for all discovered tables */
{
char *end, *end1= name +
- build_table_filename(name, sizeof(name), db, "", "");
+ build_table_filename(name, sizeof(name), db, "", "", 0);
for (i= 0; i < ok_tables.records; i++)
{
file_name= (char*)hash_element(&ok_tables, i);
@@ -6257,7 +6257,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
file_name= hash_element(&ndb_tables, i);
if (!hash_search(&ok_tables, file_name, strlen(file_name)))
{
- build_table_filename(name, sizeof(name), db, file_name, reg_ext);
+ build_table_filename(name, sizeof(name), db, file_name, reg_ext, 0);
if (my_access(name, F_OK))
{
DBUG_PRINT("info", ("%s must be discovered", file_name));
@@ -6808,7 +6808,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
NDB_SHARE *share;
DBUG_ENTER("ndb_get_commitcount");
- build_table_filename(name, sizeof(name), dbname, tabname, "");
+ build_table_filename(name, sizeof(name), dbname, tabname, "", 0);
DBUG_PRINT("enter", ("name: %s", name));
pthread_mutex_lock(&ndbcluster_mutex);
if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 8e9f0077dd0..ee9e639199c 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -737,7 +737,7 @@ static int ndbcluster_create_apply_status_table(THD *thd)
*/
{
build_table_filename(buf, sizeof(buf),
- NDB_REP_DB, NDB_APPLY_TABLE, reg_ext);
+ NDB_REP_DB, NDB_APPLY_TABLE, reg_ext, 0);
my_delete(buf, MYF(0));
}
@@ -786,7 +786,7 @@ static int ndbcluster_create_schema_table(THD *thd)
*/
{
build_table_filename(buf, sizeof(buf),
- NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext);
+ NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext, 0);
my_delete(buf, MYF(0));
}
@@ -1247,7 +1247,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
NDB_SCHEMA_OBJECT *ndb_schema_object;
{
char key[FN_REFLEN];
- build_table_filename(key, sizeof(key), db, table_name, "");
+ build_table_filename(key, sizeof(key), db, table_name, "", 0);
ndb_schema_object= ndb_get_schema_object(key, TRUE, FALSE);
}
@@ -1577,7 +1577,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
DBUG_PRINT("info", ("Detected frm change of table %s.%s",
dbname, tabname));
- build_table_filename(key, FN_LEN-1, dbname, tabname, NullS);
+ build_table_filename(key, FN_LEN-1, dbname, tabname, NullS, 0);
/*
If the frm of the altered table is different than the one on
disk then overwrite it with the new table definition
@@ -1775,7 +1775,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
case SOT_TRUNCATE_TABLE:
{
char key[FN_REFLEN];
- build_table_filename(key, sizeof(key), schema->db, schema->name, "");
+ build_table_filename(key, sizeof(key),
+ schema->db, schema->name, "", 0);
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
// invalidation already handled by binlog thread
if (!share || !share->op)
@@ -1979,7 +1980,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
{
enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
char key[FN_REFLEN];
- build_table_filename(key, sizeof(key), schema->db, schema->name, "");
+ build_table_filename(key, sizeof(key), schema->db, schema->name, "", 0);
if (schema_type == SOT_CLEAR_SLOCK)
{
pthread_mutex_lock(&ndbcluster_mutex);
diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h
index 58bf7517df5..4c3cd105d1d 100644
--- a/sql/ha_ndbcluster_binlog.h
+++ b/sql/ha_ndbcluster_binlog.h
@@ -23,7 +23,7 @@ typedef NdbDictionary::Index NDBINDEX;
typedef NdbDictionary::Dictionary NDBDICT;
typedef NdbDictionary::Event NDBEVENT;
-#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix) || is_prefix(A, "@0023sql"))
+#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix))
extern ulong ndb_extra_logging;
diff --git a/sql/item.cc b/sql/item.cc
index 4d6dc8ae754..be15bd528bb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1456,7 +1456,8 @@ bool agg_item_charsets(DTCollation &coll, const char *fname,
In case we're in statement prepare, create conversion item
in its memory: it will be reused on each execute.
*/
- arena= thd->activate_stmt_arena_if_needed(&backup);
+ arena= thd->is_stmt_prepare() ? thd->activate_stmt_arena_if_needed(&backup)
+ : NULL;
for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
{
@@ -1491,7 +1492,7 @@ bool agg_item_charsets(DTCollation &coll, const char *fname,
been created in prepare. In this case register the change for
rollback.
*/
- if (arena && arena->is_conventional())
+ if (arena)
*arg= conv;
else
thd->change_item_tree(arg, conv);
@@ -6148,14 +6149,13 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
}
- else
- max_length= max(max_length, display_length(item));
-
+
switch (Field::result_merge_type(fld_type))
{
case STRING_RESULT:
{
const char *old_cs, *old_derivation;
+ uint32 old_max_chars= max_length / collation.collation->mbmaxlen;
old_cs= collation.collation->name;
old_derivation= collation.derivation_name();
if (collation.aggregate(item->collation, MY_COLL_ALLOW_CONV))
@@ -6167,6 +6167,14 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
"UNION");
DBUG_RETURN(TRUE);
}
+ /*
+ To figure out max_length, we have to take into account possible
+ expansion of the size of the values because of character set
+ conversions.
+ */
+ max_length= max(old_max_chars * collation.collation->mbmaxlen,
+ display_length(item) / item->collation.collation->mbmaxlen *
+ collation.collation->mbmaxlen);
break;
}
case REAL_RESULT:
@@ -6185,7 +6193,8 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
max_length= (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7;
break;
}
- default:;
+ default:
+ max_length= max(max_length, display_length(item));
};
maybe_null|= item->maybe_null;
get_full_info(item);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e901eaf8654..9a2ef4e5482 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3412,6 +3412,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->length=0;
entry->update_query_id=0;
entry->collation.set(NULL, DERIVATION_IMPLICIT);
+ entry->unsigned_flag= 0;
/*
If we are here, we were called from a SET or a query which sets a
variable. Imagine it is this:
@@ -3498,6 +3499,7 @@ Item_func_set_user_var::fix_length_and_dec()
type - type of new value
cs - charset info for new value
dv - derivation for new value
+ unsigned_arg - indiates if a value of type INT_RESULT is unsigned
RETURN VALUE
False - success, True - failure
@@ -3505,7 +3507,8 @@ Item_func_set_user_var::fix_length_and_dec()
static bool
update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
- Item_result type, CHARSET_INFO *cs, Derivation dv)
+ Item_result type, CHARSET_INFO *cs, Derivation dv,
+ bool unsigned_arg)
{
if (set_null)
{
@@ -3553,6 +3556,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
((my_decimal*)entry->value)->fix_buffer_pointer();
entry->length= length;
entry->collation.set(cs, dv);
+ entry->unsigned_flag= unsigned_arg;
}
entry->type=type;
return 0;
@@ -3561,7 +3565,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
bool
Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
- CHARSET_INFO *cs, Derivation dv)
+ CHARSET_INFO *cs, Derivation dv,
+ bool unsigned_arg)
{
/*
If we set a variable explicitely to NULL then keep the old
@@ -3570,7 +3575,7 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
if ((null_value= args[0]->null_value) && null_item)
type= entry->type; // Don't change type of item
if (::update_hash(entry, (null_value= args[0]->null_value),
- ptr, length, type, cs, dv))
+ ptr, length, type, cs, dv, unsigned_arg))
{
current_thd->fatal_error(); // Probably end of memory
null_value= 1;
@@ -3652,7 +3657,10 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
str->set_real(*(double*) value, decimals, &my_charset_bin);
break;
case INT_RESULT:
- str->set(*(longlong*) value, &my_charset_bin);
+ if (!unsigned_flag)
+ str->set(*(longlong*) value, &my_charset_bin);
+ else
+ str->set(*(ulonglong*) value, &my_charset_bin);
break;
case DECIMAL_RESULT:
my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str);
@@ -3723,6 +3731,7 @@ Item_func_set_user_var::check()
case INT_RESULT:
{
save_result.vint= args[0]->val_int();
+ unsigned_flag= args[0]->unsigned_flag;
break;
}
case STRING_RESULT:
@@ -3778,7 +3787,8 @@ Item_func_set_user_var::update()
case INT_RESULT:
{
res= update_hash((void*) &save_result.vint, sizeof(save_result.vint),
- INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT);
+ INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT,
+ unsigned_flag);
break;
}
case STRING_RESULT:
@@ -4157,7 +4167,7 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs)
{
if (::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs,
- DERIVATION_IMPLICIT))
+ DERIVATION_IMPLICIT, 0 /* unsigned_arg */))
current_thd->fatal_error(); // Probably end of memory
}
@@ -4166,7 +4176,7 @@ void Item_user_var_as_out_param::set_value(const char *str, uint length,
CHARSET_INFO* cs)
{
if (::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs,
- DERIVATION_IMPLICIT))
+ DERIVATION_IMPLICIT, 0 /* unsigned_arg */))
current_thd->fatal_error(); // Probably end of memory
}
@@ -4837,7 +4847,9 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
{
bool err_status= TRUE;
Sub_statement_state statement_state;
- Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_security_ctx= thd->security_ctx;
+#endif
DBUG_ENTER("Item_func_sp::execute_impl");
@@ -4848,7 +4860,7 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
thd->security_ctx= context->security_ctx;
}
#endif
- if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx_func))
+ if (find_and_check_access(thd))
goto error;
/*
@@ -4860,13 +4872,11 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
thd->restore_sub_statement_state(&statement_state);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sp_restore_security_context(thd, save_ctx_func);
error:
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->security_ctx= save_security_ctx;
-#else
-error:
#endif
+
DBUG_RETURN(err_status);
}
@@ -4983,70 +4993,38 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
SYNOPSIS
find_and_check_access()
thd thread handler
- want_access requested access
- save backup of security context
RETURN
FALSE Access granted
TRUE Requested access can't be granted or function doesn't exists
- In this case security context is not changed and *save = 0
NOTES
Checks if requested access to function can be granted to user.
If function isn't found yet, it searches function first.
If function can't be found or user don't have requested access
error is raised.
- If security context sp_ctx is provided and access can be granted then
- switch back to previous context isn't performed.
- In case of access error or if context is not provided then
- find_and_check_access() switches back to previous security context.
*/
bool
-Item_func_sp::find_and_check_access(THD *thd, ulong want_access,
- Security_context **save)
+Item_func_sp::find_and_check_access(THD *thd)
{
- bool res= TRUE;
-
- *save= 0; // Safety if error
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;
+ return TRUE;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_routine_access(thd, want_access,
- m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
- goto error;
-
- sp_change_security_context(thd, m_sp, save);
- /*
- If we changed context to run as another user, we need to check the
- access right for the new context again as someone may have deleted
- this person the right to use the procedure
-
- TODO:
- Cache if the definer has the right to use the object on the first
- usage and only reset the cache if someone does a GRANT statement
- that 'may' affect this.
- */
- if (*save &&
- check_routine_access(thd, want_access,
+ if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
- {
- sp_restore_security_context(thd, *save);
- *save= 0; // Safety
- goto error;
- }
+ return TRUE;
#endif
- res= FALSE; // no error
-error:
- return res;
+ return FALSE;
}
+
bool
Item_func_sp::fix_fields(THD *thd, Item **ref)
{
@@ -5057,19 +5035,23 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
{
/*
Here we check privileges of the stored routine only during view
- creation, in order to validate the view. A runtime check is perfomed
- in Item_func_sp::execute(), and this method is not called during
- context analysis. We do not need to restore the security context
- changed in find_and_check_access because all view structures created
- in CREATE VIEW are not used for execution. Notice, that during view
- creation we do not infer into stored routine bodies and do not check
- privileges of its statements, which would probably be a good idea
- especially if the view has SQL SECURITY DEFINER and the used stored
- procedure has SQL SECURITY DEFINER
+ creation, in order to validate the view. A runtime check is
+ perfomed in Item_func_sp::execute(), and this method is not
+ called during context analysis. Notice, that during view
+ creation we do not infer into stored routine bodies and do not
+ check privileges of its statements, which would probably be a
+ good idea especially if the view has SQL SECURITY DEFINER and
+ the used stored procedure has SQL SECURITY DEFINER.
*/
- Security_context *save_ctx;
- if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
- sp_restore_security_context(thd, save_ctx);
+ res= find_and_check_access(thd);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_secutiry_ctx;
+ if (!res && !(res= set_routine_security_ctx(thd, m_sp, false,
+ &save_secutiry_ctx)))
+ {
+ sp_restore_security_context(thd, save_secutiry_ctx);
+ }
+#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
}
return res;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 3a1952c8d0f..168430a5a11 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1190,8 +1190,6 @@ class Item_func_set_user_var :public Item_func
String *vstr;
my_decimal *vdec;
} save_result;
- String save_buff;
-
public:
LEX_STRING name; // keep it public
@@ -1202,8 +1200,8 @@ public:
longlong val_int();
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool update_hash(void *ptr, uint length, enum Item_result type,
- CHARSET_INFO *cs, Derivation dv);
+ bool update_hash(void *ptr, uint length, enum Item_result type,
+ CHARSET_INFO *cs, Derivation dv, bool unsigned_arg= 0);
bool check();
bool update();
enum Item_result result_type () const { return cached_result_type; }
@@ -1502,8 +1500,7 @@ public:
{ context= (Name_resolution_context *)cntx; return FALSE; }
void fix_length_and_dec();
- bool find_and_check_access(THD * thd, ulong want_access,
- Security_context **backup);
+ bool find_and_check_access(THD * thd);
virtual enum Functype functype() const { return FUNC_SP; }
bool fix_fields(THD *thd, Item **ref);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index dee7f408733..23c7cb4c3d8 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2985,6 +2985,16 @@ String *Item_func_uncompress::val_str(String *str)
if (res->is_empty())
return res;
+ /* If length is less than 4 bytes, data is corrupt */
+ if (res->length() <= 4)
+ {
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ZLIB_Z_DATA_ERROR,
+ ER(ER_ZLIB_Z_DATA_ERROR));
+ goto err;
+ }
+
+ /* Size of uncompressed data is stored as first 4 bytes of field */
new_size= uint4korr(res->ptr()) & 0x3FFFFFFF;
if (new_size > current_thd->variables.max_allowed_packet)
{
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index e085c0b4d7b..1b843b27203 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -831,7 +831,7 @@ class Item_func_uncompress: public Item_str_func
String buffer;
public:
Item_func_uncompress(Item *a): Item_str_func(a){}
- void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;}
+ void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; }
const char *func_name() const{return "uncompress";}
String *val_str(String *) ZLIB_DEPENDED_FUNCTION
bool check_partition_func_processor(byte *bool_arg) { return 0;}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 7dfe65d793a..e24a57809f2 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1554,6 +1554,7 @@ static Item_result set_row(List<Item> &item_list, Item *item,
item->max_length= sel_item->max_length;
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
+ item->unsigned_flag= sel_item->unsigned_flag;
*maybe_null= sel_item->maybe_null;
if (!(row[i]= Item_cache::get_cache(res_type)))
return STRING_RESULT; // we should return something
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 024b0ecfb42..58935337aa0 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1278,11 +1278,10 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
sizeof(double)*2) + sizeof(longlong),
0, name, &my_charset_bin);
}
- else if (hybrid_type == DECIMAL_RESULT)
- field= new Field_new_decimal(max_length, maybe_null, name,
- decimals, unsigned_flag);
else
- field= new Field_double(max_length, maybe_null, name, decimals);
+ {
+ field= new Field_double(max_length, maybe_null,name, decimals);
+ }
if (field)
field->init(table);
return field;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index a0cd08dcb11..3679780db60 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -688,7 +688,7 @@ public:
{ return sample ? "var_samp(" : "variance("; }
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
- enum Item_result result_type () const { return hybrid_type; }
+ enum Item_result result_type () const { return REAL_RESULT; }
};
class Item_sum_std;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 2c8d8423d50..e0c80087c05 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2756,6 +2756,8 @@ longlong Item_func_timestamp_diff::val_int()
{
uint year_beg, year_end, month_beg, month_end, day_beg, day_end;
uint years= 0;
+ uint second_beg, second_end, microsecond_beg, microsecond_end;
+
if (neg == -1)
{
year_beg= ltime2.year;
@@ -2764,6 +2766,10 @@ longlong Item_func_timestamp_diff::val_int()
month_end= ltime1.month;
day_beg= ltime2.day;
day_end= ltime1.day;
+ second_beg= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
+ second_end= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
+ microsecond_beg= ltime2.second_part;
+ microsecond_end= ltime1.second_part;
}
else
{
@@ -2773,6 +2779,10 @@ longlong Item_func_timestamp_diff::val_int()
month_end= ltime2.month;
day_beg= ltime1.day;
day_end= ltime2.day;
+ second_beg= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
+ second_end= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
+ microsecond_beg= ltime1.second_part;
+ microsecond_end= ltime2.second_part;
}
/* calc years */
@@ -2786,8 +2796,13 @@ longlong Item_func_timestamp_diff::val_int()
months+= 12 - (month_beg - month_end);
else
months+= (month_end - month_beg);
+
if (day_end < day_beg)
months-= 1;
+ else if ((day_end == day_beg) &&
+ ((second_end < second_beg) ||
+ (second_end == second_beg && microsecond_end < microsecond_beg)))
+ months-= 1;
}
switch (int_type) {
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 651b0405842..74894e1fe64 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -754,7 +754,7 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
bool if_exists, bool drop_temporary,
bool log_query);
bool quick_rm_table(handlerton *base,const char *db,
- const char *table_name);
+ const char *table_name, uint flags);
void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
@@ -899,11 +899,9 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
HA_CREATE_INFO *create_info,
Table_ident *src_table);
-bool mysql_rename_table(handlerton *base,
- const char *old_db,
- const char * old_name,
- const char *new_db,
- const char * new_name);
+bool mysql_rename_table(handlerton *base, const char *old_db,
+ const char * old_name, const char *new_db,
+ const char * new_name, uint flags);
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
ALTER_INFO *alter_info);
@@ -1019,8 +1017,6 @@ bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
int mysqld_show_variables(THD *thd,const char *wild);
-int mysql_find_files(THD *thd,List<char> *files, const char *db,
- const char *path, const char *wild, bool dir);
bool mysqld_show_storage_engines(THD *thd);
bool mysqld_show_authors(THD *thd);
bool mysqld_show_contributors(THD *thd);
@@ -1464,7 +1460,11 @@ bool is_keyword(const char *name, uint len);
#define MY_DB_OPT_FILE "db.opt"
bool my_database_names_init(void);
void my_database_names_free(void);
+bool check_db_dir_existence(const char *db_name);
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
+bool load_db_opt_by_name(THD *thd, const char *db_name,
+ HA_CREATE_INFO *db_create_info);
+bool my_dbopt_init(void);
void my_dbopt_cleanup(void);
extern int creating_database; // How many database locks are made
extern int creating_table; // How many mysql_create_table() are running
@@ -1850,7 +1850,12 @@ uint strconvert(CHARSET_INFO *from_cs, const char *from,
uint filename_to_tablename(const char *from, char *to, uint to_length);
uint tablename_to_filename(const char *from, char *to, uint to_length);
uint build_table_filename(char *buff, size_t bufflen, const char *db,
- const char *table, const char *ext);
+ const char *table, const char *ext, uint flags);
+/* Flags for conversion functions. */
+#define FN_FROM_IS_TMP (1 << 0)
+#define FN_TO_IS_TMP (1 << 1)
+#define FN_IS_TMP (FN_FROM_IS_TMP | FN_TO_IS_TMP)
+
/* from hostname.cc */
struct in_addr;
my_string ip_to_hostname(struct in_addr *in,uint *errors);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 087613c6b7c..b4558dec35e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2837,6 +2837,11 @@ You should consider changing lower_case_table_names to 1 or 2",
mysql_real_data_home);
lower_case_table_names= 0;
}
+ else
+ {
+ lower_case_file_system=
+ (test_if_case_insensitive(mysql_real_data_home) == 1);
+ }
/* Reset table_alias_charset, now that lower_case_table_names is set. */
table_alias_charset= (lower_case_table_names ?
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 2edc11b6b3e..46d28a16c58 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -322,7 +322,7 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
254 Marker (1 byte)
warning_count Stored in 2 bytes; New in 4.1 protocol
status_flag Stored in 2 bytes;
- For flags like SERVER_STATUS_MORE_RESULTS
+ For flags like SERVER_MORE_RESULTS_EXISTS
Note that the warning count will not be sent if 'no_flush' is set as
we don't want to report the warning count until all data is sent to the
diff --git a/sql/slave.cc b/sql/slave.cc
index 19060eba2d4..84d97242bf3 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2823,7 +2823,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
DBUG_RETURN(packet_error);
#endif
- len = net_safe_read(mysql);
+ len = cli_safe_read(mysql);
if (len == packet_error || (long) len < 1)
{
if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
diff --git a/sql/sp.cc b/sql/sp.cc
index f60a167e39a..b7671803cf5 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -497,6 +497,13 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
table.s = &share;
field= sp->create_result_field(0, 0, &table);
field->sql_type(result);
+
+ if (field->has_charset())
+ {
+ result.append(STRING_WITH_LEN(" CHARSET "));
+ result.append(field->charset()->csname);
+ }
+
delete field;
}
@@ -628,7 +635,10 @@ db_create_routine(THD *thd, int type, sp_head *sp)
log_query.append(STRING_WITH_LEN("CREATE "));
append_definer(thd, &log_query, &thd->lex->definer->user,
&thd->lex->definer->host);
- log_query.append(thd->lex->stmt_definition_begin);
+ log_query.append(thd->lex->stmt_definition_begin,
+ (char *)sp->m_body_begin -
+ thd->lex->stmt_definition_begin +
+ sp->m_body.length);
/* Such a statement can always go directly to binlog, no trans cache */
thd->binlog_query(THD::MYSQL_QUERY_TYPE,
@@ -975,6 +985,11 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
sp_head *new_sp;
const char *returns= "";
char definer[USER_HOST_BUFF_SIZE];
+
+ /*
+ String buffer for RETURNS data type must have system charset;
+ 64 -- size of "returns" column of mysql.proc.
+ */
String retstr(64);
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 8368e828fdc..b88ff13cd7a 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -450,7 +450,14 @@ sp_head::sp_head()
m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this),
m_cont_level(0)
{
+ const LEX_STRING str_reset= { NULL, 0 };
m_return_field_def.charset = NULL;
+ /*
+ FIXME: the only use case when name is NULL is events, and it should
+ be rewritten soon. Remove the else part and replace 'if' with
+ an assert when this is done.
+ */
+ m_db= m_name= m_qname= str_reset;
extern byte *
sp_table_key(const byte *ptr, uint *plen, my_bool first);
@@ -479,7 +486,7 @@ sp_head::init(LEX *lex)
lex->trg_table_fields.empty();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
m_param_begin= m_param_end= m_body_begin= 0;
- m_qname.str= m_db.str= m_name.str= m_params.str=
+ m_qname.str= m_db.str= m_name.str= m_params.str=
m_body.str= m_defstr.str= 0;
m_qname.length= m_db.length= m_name.length= m_params.length=
m_body.length= m_defstr.length= 0;
@@ -487,41 +494,44 @@ sp_head::init(LEX *lex)
DBUG_VOID_RETURN;
}
+
void
-sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
+sp_head::init_sp_name(THD *thd, sp_name *spname)
+{
+ DBUG_ENTER("sp_head::init_sp_name");
+
+ /* Must be initialized in the parser. */
+
+ DBUG_ASSERT(spname && spname->m_db.str && spname->m_db.length);
+
+ /* We have to copy strings to get them into the right memroot. */
+
+ m_db.length= spname->m_db.length;
+ m_db.str= strmake_root(thd->mem_root, spname->m_db.str, spname->m_db.length);
+
+ m_name.length= spname->m_name.length;
+ m_name.str= strmake_root(thd->mem_root, spname->m_name.str,
+ spname->m_name.length);
+
+ if (spname->m_qname.length == 0)
+ spname->init_qname(thd);
+
+ m_qname.length= spname->m_qname.length;
+ m_qname.str= strmake_root(thd->mem_root, spname->m_qname.str,
+ m_qname.length);
+
+ DBUG_VOID_RETURN;
+}
+
+
+void
+sp_head::init_strings(THD *thd, LEX *lex)
{
DBUG_ENTER("sp_head::init_strings");
const uchar *endp; /* Used to trim the end */
/* During parsing, we must use thd->mem_root */
MEM_ROOT *root= thd->mem_root;
- if (name)
- {
- /* Must be initialized in the parser */
- DBUG_ASSERT(name->m_db.str && name->m_db.length);
-
- /* We have to copy strings to get them into the right memroot */
- m_db.length= name->m_db.length;
- m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
- m_name.length= name->m_name.length;
- m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
-
- if (name->m_qname.length == 0)
- name->init_qname(thd);
- m_qname.length= name->m_qname.length;
- m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
- }
- else
- {
- /*
- FIXME: the only use case when name is NULL is events, and it should
- be rewritten soon. Remove the else part and replace 'if' with
- an assert when this is done.
- */
- LEX_STRING str_reset= { NULL, 0 };
- m_db= m_name= m_qname= str_reset;
- }
-
if (m_param_begin && m_param_end)
{
m_params.length= m_param_end - m_param_begin;
@@ -535,10 +545,7 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
Trim "garbage" at the end. This is sometimes needed with the
"/ * ! VERSION... * /" wrapper in dump files.
*/
- while (m_body_begin < endp &&
- (endp[-1] <= ' ' || endp[-1] == '*' ||
- endp[-1] == '/' || endp[-1] == ';'))
- endp-= 1;
+ endp= skip_rear_comments(m_body_begin, endp);
m_body.length= endp - m_body_begin;
m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
@@ -1125,6 +1132,7 @@ sp_head::execute(THD *thd)
thd->restore_active_arena(&execute_arena, &backup_arena);
+ thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error
/* Restore all saved */
old_packet.swap(thd->packet);
@@ -1186,6 +1194,135 @@ sp_head::execute(THD *thd)
m_first_instance->m_first_free_instance->m_recursion_level ==
m_recursion_level + 1));
m_first_instance->m_first_free_instance= this;
+
+ DBUG_RETURN(err_status);
+}
+
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/*
+ set_routine_security_ctx() changes routine security context, and
+ checks if there is an EXECUTE privilege in new context. If there is
+ no EXECUTE privilege, it changes the context back and returns a
+ error.
+
+ SYNOPSIS
+ set_routine_security_ctx()
+ thd thread handle
+ sp stored routine to change the context for
+ is_proc TRUE is procedure, FALSE if function
+ save_ctx pointer to an old security context
+
+ RETURN
+ TRUE if there was a error, and the context wasn't changed.
+ FALSE if the context was changed.
+*/
+
+bool
+set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
+ Security_context **save_ctx)
+{
+ *save_ctx= 0;
+ if (sp_change_security_context(thd, sp, save_ctx))
+ return TRUE;
+
+ /*
+ If we changed context to run as another user, we need to check the
+ access right for the new context again as someone may have revoked
+ the right to use the procedure from this user.
+
+ TODO:
+ Cache if the definer has the right to use the object on the
+ first usage and only reset the cache if someone does a GRANT
+ statement that 'may' affect this.
+ */
+ if (*save_ctx &&
+ check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, is_proc, FALSE))
+ {
+ sp_restore_security_context(thd, *save_ctx);
+ *save_ctx= 0;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif // ! NO_EMBEDDED_ACCESS_CHECKS
+
+
+/*
+ Execute a trigger:
+ - changes security context for triggers
+ - switch to new memroot
+ - call sp_head::execute
+ - restore old memroot
+ - restores security context
+
+ SYNOPSIS
+ sp_head::execute_trigger()
+ thd Thread handle
+ db database name
+ table table name
+ grant_info GRANT_INFO structure to be filled with
+ information about definer's privileges
+ on subject table
+
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool
+sp_head::execute_trigger(THD *thd, const char *db, const char *table,
+ GRANT_INFO *grant_info)
+{
+ sp_rcontext *octx = thd->spcont;
+ sp_rcontext *nctx = NULL;
+ bool err_status= FALSE;
+ MEM_ROOT call_mem_root;
+ Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
+ Query_arena backup_arena;
+
+ DBUG_ENTER("sp_head::execute_trigger");
+ DBUG_PRINT("info", ("trigger %s", m_name.str));
+
+ /*
+ Prepare arena and memroot for objects which lifetime is whole
+ duration of trigger call (sp_rcontext, it's tables and items,
+ sp_cursor and Item_cache holders for case expressions). We can't
+ use caller's arena/memroot for those objects because in this case
+ some fixed amount of memory will be consumed for each trigger
+ invocation and so statements which involve lot of them will hog
+ memory.
+
+ TODO: we should create sp_rcontext once per command and reuse it
+ on subsequent executions of a trigger.
+ */
+ init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+ thd->set_n_backup_active_arena(&call_arena, &backup_arena);
+
+ if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) ||
+ nctx->init(thd))
+ {
+ err_status= TRUE;
+ goto err_with_cleanup;
+ }
+
+#ifndef DBUG_OFF
+ nctx->sp= this;
+#endif
+
+ thd->spcont= nctx;
+
+ err_status= execute(thd);
+
+err_with_cleanup:
+ thd->restore_active_arena(&call_arena, &backup_arena);
+ delete nctx;
+ call_arena.free_items();
+ free_root(&call_mem_root, MYF(0));
+ thd->spcont= octx;
+
DBUG_RETURN(err_status);
}
@@ -1193,8 +1330,12 @@ sp_head::execute(THD *thd)
/*
Execute a function:
- evaluate parameters
+ - changes security context for SUID routines
+ - switch to new memroot
- call sp_head::execute
+ - restore old memroot
- evaluate the return value
+ - restores security context
SYNOPSIS
sp_head::execute_function()
@@ -1328,6 +1469,15 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
}
thd->spcont= nctx;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_security_ctx;
+ if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx))
+ {
+ err_status= TRUE;
+ goto err_with_cleanup;
+ }
+#endif
+
if (need_binlog_call)
{
reset_dynamic(&thd->user_var_events);
@@ -1369,7 +1519,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
}
}
- if (m_type == TYPE_ENUM_FUNCTION && !err_status)
+ if (!err_status)
{
/* We need result only in function but not in trigger */
@@ -1380,8 +1530,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
}
}
-
- nctx->pop_all_cursors(); // To avoid memory leaks after an error
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ sp_restore_security_context(thd, save_security_ctx);
+#endif
err_with_cleanup:
delete nctx;
@@ -1404,8 +1555,10 @@ err_with_cleanup:
The function does the following steps:
- Set all parameters
+ - changes security context for SUID routines
- call sp_head::execute
- copy back values of INOUT and OUT parameters
+ - restores security context
RETURN
FALSE on success
@@ -1539,7 +1692,13 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->options |= OPTION_LOG_OFF;
}
thd->spcont= nctx;
-
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_security_ctx= 0;
+ if (!err_status)
+ err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx);
+#endif
+
if (!err_status)
err_status= execute(thd);
@@ -1588,10 +1747,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (save_security_ctx)
+ sp_restore_security_context(thd, save_security_ctx);
+#endif
+
if (!save_spcont)
delete octx;
- nctx->pop_all_cursors(); // To avoid memory leaks after an error
delete nctx;
thd->spcont= save_spcont;
@@ -1623,6 +1786,7 @@ sp_head::reset_lex(THD *thd)
sublex->ptr= oldlex->ptr;
sublex->end_of_query= oldlex->end_of_query;
sublex->tok_start= oldlex->tok_start;
+ sublex->tok_end= oldlex->tok_end;
sublex->yylineno= oldlex->yylineno;
/* And keep the SP stuff too */
sublex->sphead= oldlex->sphead;
@@ -1658,6 +1822,7 @@ sp_head::restore_lex(THD *thd)
// Update some state in the old one first
oldlex->ptr= sublex->ptr;
+ oldlex->tok_end= sublex->tok_end;
oldlex->next_state= sublex->next_state;
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
@@ -1738,14 +1903,18 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
enum enum_field_types field_type,
create_field *field_def)
{
+ HA_CREATE_INFO sp_db_info;
LEX_STRING cmt = { 0, 0 };
uint unused1= 0;
int unused2= 0;
+ load_db_opt_by_name(thd, m_db.str, &sp_db_info);
+
if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
&lex->interval_list,
- (lex->charset ? lex->charset : default_charset_info),
+ (lex->charset ? lex->charset :
+ sp_db_info.default_table_charset),
lex->uint_geom_type))
return TRUE;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 4712647b6f4..3ad1e1b85f0 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -195,9 +195,13 @@ public:
void
init(LEX *lex);
+ /* Copy sp name from parser. */
+ void
+ init_sp_name(THD *thd, sp_name *spname);
+
// Initialize strings after parsing header
void
- init_strings(THD *thd, LEX *lex, sp_name *name);
+ init_strings(THD *thd, LEX *lex);
int
create(THD *thd);
@@ -209,6 +213,10 @@ public:
destroy();
bool
+ execute_trigger(THD *thd, const char *db, const char *table,
+ GRANT_INFO *grant_onfo);
+
+ bool
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
bool
@@ -1170,6 +1178,10 @@ sp_change_security_context(THD *thd, sp_head *sp,
Security_context **backup);
void
sp_restore_security_context(THD *thd, Security_context *backup);
+
+bool
+set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
+ Security_context **save_ctx);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
TABLE_LIST *
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 402cfc4de60..030a72c2847 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2962,7 +2962,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{
char buf[FN_REFLEN];
build_table_filename(buf, sizeof(buf), table_list->db,
- table_list->table_name, reg_ext);
+ table_list->table_name, reg_ext, 0);
fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS |
MY_RETURN_REAL_PATH | MY_APPEND_EXT);
if (access(buf,F_OK))
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index dbe7f5b5083..1c733e3c12d 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -39,7 +39,7 @@ static bool table_def_inited= 0;
static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
const char *alias,
char *cache_key, uint cache_key_length,
- MEM_ROOT *mem_root);
+ MEM_ROOT *mem_root, uint flags);
static void free_cache_entry(TABLE *entry);
static void mysql_rm_tmp_tables(void);
static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
@@ -254,7 +254,7 @@ uint cached_table_definitions(void)
Get TABLE_SHARE for a table.
get_table_share()
- thd Table share
+ thd Thread handle
table_list Table that should be opened
key Table cache key
key_length Length of key
@@ -1500,15 +1500,18 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
char key[MAX_DBKEY_LENGTH];
uint key_length;
TABLE *table;
+ DBUG_ENTER("find_temporary_table");
+ DBUG_PRINT("enter", ("table: '%s'.'%s'",
+ table_list->db, table_list->table_name));
key_length= create_table_def_key(thd, key, table_list, 1);
for (table=thd->temporary_tables ; table ; table= table->next)
{
if (table->s->table_cache_key.length == key_length &&
!memcmp(table->s->table_cache_key.str, key, key_length))
- return table;
+ DBUG_RETURN(table);
}
- return 0; // Not a temporary table
+ DBUG_RETURN(0); // Not a temporary table
}
@@ -1763,7 +1766,7 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
if (open_unireg_entry(thd, table, table_list, table_name,
table->s->table_cache_key.str,
- table->s->table_cache_key.length, thd->mem_root))
+ table->s->table_cache_key.length, thd->mem_root, 0))
{
intern_close_table(table);
/*
@@ -1949,7 +1952,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
char path[FN_REFLEN];
enum legacy_db_type not_used;
build_table_filename(path, sizeof(path) - 1,
- table_list->db, table_list->table_name, reg_ext);
+ table_list->db, table_list->table_name, reg_ext, 0);
if (mysql_frm_type(thd, path, &not_used) == FRMTYPE_VIEW)
{
/*
@@ -1960,7 +1963,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table= &tab;
VOID(pthread_mutex_lock(&LOCK_open));
if (!open_unireg_entry(thd, table, table_list, alias,
- key, key_length, mem_root))
+ key, key_length, mem_root, 0))
{
DBUG_ASSERT(table_list->view != 0);
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -2044,6 +2047,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
else
{
+ int error;
/* Free cache if too big */
while (open_cache.records > table_cache_size && unused_tables)
VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
@@ -2055,15 +2059,23 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
DBUG_RETURN(NULL);
}
- if (open_unireg_entry(thd, table, table_list, alias, key, key_length,
- mem_root))
+ error= open_unireg_entry(thd, table, table_list, alias, key, key_length,
+ mem_root, (flags & OPEN_VIEW_NO_PARSE));
+ if (error > 0)
{
my_free((gptr)table, MYF(0));
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(NULL);
}
- if (table_list->view)
+ if (table_list->view || error < 0)
{
+ /*
+ VIEW not really opened, only frm were read.
+ Set 1 as a flag here
+ */
+ if (error < 0)
+ table_list->view= (st_lex*)1;
+
my_free((gptr)table, MYF(0));
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(0); // VIEW
@@ -2165,7 +2177,6 @@ static bool reopen_table(TABLE *table)
sql_print_error("Table %s had a open data handler in reopen_table",
table->alias);
#endif
-
table_list.db= table->s->db.str;
table_list.table_name= table->s->table_name.str;
table_list.table= table;
@@ -2179,7 +2190,7 @@ static bool reopen_table(TABLE *table)
table->alias,
table->s->table_cache_key.str,
table->s->table_cache_key.length,
- thd->mem_root))
+ thd->mem_root, 0))
goto end;
/* This list copies variables set by open_table */
@@ -2617,6 +2628,8 @@ void assign_new_table_id(TABLE_SHARE *share)
cache_key Key for share_cache
cache_key_length length of cache_key
mem_root temporary mem_root for parsing
+ flags the OPEN_VIEW_NO_PARSE flag to be passed to
+ openfrm()/open_new_frm()
NOTES
Extra argument for open is taken from thd->open_options
@@ -2630,7 +2643,7 @@ void assign_new_table_id(TABLE_SHARE *share)
static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
const char *alias,
char *cache_key, uint cache_key_length,
- MEM_ROOT *mem_root)
+ MEM_ROOT *mem_root, uint flags)
{
int error;
TABLE_SHARE *share;
@@ -2651,14 +2664,15 @@ retry:
error= (int) open_new_frm(thd, share, alias,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
HA_GET_INDEX | HA_TRY_READ_ONLY),
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
+ (flags & OPEN_VIEW_NO_PARSE),
thd->open_options, entry, table_list,
mem_root);
if (error)
goto err;
/* TODO: Don't free this */
release_table_share(share, RELEASE_NORMAL);
- DBUG_RETURN(0);
+ DBUG_RETURN((flags & OPEN_VIEW_NO_PARSE)? -1 : 0);
}
while ((error= open_table_from_share(thd, share, alias,
@@ -2711,7 +2725,6 @@ retry:
}
if (!entry->s || !entry->s->crashed)
goto err;
-
// Code below is for repairing a crashed file
if ((error= lock_table_name(thd, table_list, TRUE)))
{
@@ -3501,6 +3514,8 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
uint key_length;
TABLE_LIST table_list;
DBUG_ENTER("open_temporary_table");
+ DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'",
+ db, table_name, path));
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
@@ -6343,7 +6358,8 @@ open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
"BASE TABLE");
goto err;
}
- if (mysql_make_view(thd, parser, table_desc))
+ if (mysql_make_view(thd, parser, table_desc,
+ (prgflag & OPEN_VIEW_NO_PARSE)))
goto err;
}
else
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 31b97cf5982..6b46c9676f7 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2018,6 +2018,7 @@ class user_var_entry
ulong length;
query_id_t update_query_id, used_query_id;
Item_result type;
+ bool unsigned_flag;
double val_real(my_bool *null_value);
longlong val_int(my_bool *null_value);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 77d99862bf0..372a350566f 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -408,7 +408,6 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
create Where to store the read options
DESCRIPTION
- For now, only default-character-set is read.
RETURN VALUES
0 File found
@@ -497,6 +496,52 @@ err1:
/*
+ Retrieve database options by name. Load database options file or fetch from
+ cache.
+
+ SYNOPSIS
+ load_db_opt_by_name()
+ db_name Database name
+ db_create_info Where to store the database options
+
+ DESCRIPTION
+ load_db_opt_by_name() is a shortcut for load_db_opt().
+
+ NOTE
+ Although load_db_opt_by_name() (and load_db_opt()) returns status of
+ the operation, it is useless usually and should be ignored. The problem
+ is that there are 1) system databases ("mysql") and 2) virtual
+ databases ("information_schema"), which do not contain options file.
+ So, load_db_opt[_by_name]() returns FALSE for these databases, but this
+ is not an error.
+
+ load_db_opt[_by_name]() clears db_create_info structure in any case, so
+ even on failure it contains valid data. So, common use case is just
+ call load_db_opt[_by_name]() without checking return value and use
+ db_create_info right after that.
+
+ RETURN VALUES (read NOTE!)
+ FALSE Success
+ TRUE Failed to retrieve options
+*/
+
+bool load_db_opt_by_name(THD *thd, const char *db_name,
+ HA_CREATE_INFO *db_create_info)
+{
+ char db_opt_path[FN_REFLEN];
+
+ /*
+ Pass an empty file name, and the database options file name as extension
+ to avoid table name to file name encoding.
+ */
+ (void) build_table_filename(db_opt_path, sizeof(db_opt_path),
+ db_name, "", MY_DB_OPT_FILE, 0);
+
+ return load_db_opt(thd, db_opt_path, db_create_info);
+}
+
+
+/*
Create a database
SYNOPSIS
@@ -560,7 +605,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
/* Check directory */
- path_len= build_table_filename(path, sizeof(path), db, "", "");
+ path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
path[path_len-1]= 0; // Remove last '/' from path
if (my_stat(path,&stat_info,MYF(0)))
@@ -704,7 +749,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
We pass MY_DB_OPT_FILE as "extension" to avoid
"table name to file name" encoding.
*/
- build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE);
+ build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0);
if ((error=write_db_opt(thd, path, create_info)))
goto exit;
@@ -797,7 +842,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- length= build_table_filename(path, sizeof(path), db, "", "");
+ length= build_table_filename(path, sizeof(path), db, "", "", 0);
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
del_dbopt(path); // Remove dboption hash entry
path[length]= '\0'; // Remove file name
@@ -1254,8 +1299,6 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
{
int path_length, db_length;
char *db_name;
- char path[FN_REFLEN];
- HA_CREATE_INFO create;
bool system_db= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
@@ -1324,15 +1367,14 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
}
}
#endif
- path_length= build_table_filename(path, sizeof(path), db_name, "", "");
- if (path_length && path[path_length-1] == FN_LIBCHAR)
- path[path_length-1]= '\0'; // remove ending '\'
- if (my_access(path,F_OK))
+
+ if (check_db_dir_existence(db_name))
{
my_error(ER_BAD_DB_ERROR, MYF(0), db_name);
my_free(db_name, MYF(0));
DBUG_RETURN(1);
}
+
end:
x_free(thd->db);
DBUG_ASSERT(db_name == NULL || db_name[0] != '\0');
@@ -1348,8 +1390,10 @@ end:
}
else
{
- strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
+ HA_CREATE_INFO create;
+
+ load_db_opt_by_name(thd, db_name, &create);
+
thd->db_charset= create.default_table_charset ?
create.default_table_charset :
thd->variables.collation_server;
@@ -1469,11 +1513,12 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
if (thd->db && !strcmp(thd->db, old_db->str))
change_to_newdb= 1;
- build_table_filename(path, sizeof(path)-1, old_db->str, "", MY_DB_OPT_FILE);
+ build_table_filename(path, sizeof(path)-1,
+ old_db->str, "", MY_DB_OPT_FILE, 0);
if ((load_db_opt(thd, path, &create_info)))
create_info.default_table_charset= thd->variables.collation_server;
- length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "");
+ length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0);
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
if ((error= my_access(path,F_OK)))
@@ -1538,9 +1583,10 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
If some tables were left in the new directory, rmdir() will fail.
It garantees we never loose any tables.
*/
- build_table_filename(path, sizeof(path)-1, new_db->str,"",MY_DB_OPT_FILE);
+ build_table_filename(path, sizeof(path)-1,
+ new_db->str,"",MY_DB_OPT_FILE, 0);
my_delete(path, MYF(MY_WME));
- length= build_table_filename(path, sizeof(path)-1, new_db->str, "", "");
+ length= build_table_filename(path, sizeof(path)-1, new_db->str, "", "", 0);
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
rmdir(path);
@@ -1592,9 +1638,9 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
/* pass empty file name, and file->name as extension to avoid encoding */
build_table_filename(oldname, sizeof(oldname)-1,
- old_db->str, "", file->name);
+ old_db->str, "", file->name, 0);
build_table_filename(newname, sizeof(newname)-1,
- new_db->str, "", file->name);
+ new_db->str, "", file->name, 0);
my_rename(oldname, newname, MYF(MY_WME));
}
my_dirend(dirp);
@@ -1666,3 +1712,31 @@ exit:
DBUG_RETURN(error);
}
+
+/*
+ Check if there is directory for the database name.
+
+ SYNOPSIS
+ check_db_dir_existence()
+ db_name database name
+
+ RETURN VALUES
+ FALSE There is directory for the specified database name.
+ TRUE The directory does not exist.
+*/
+
+bool check_db_dir_existence(const char *db_name)
+{
+ char db_dir_path[FN_REFLEN];
+ uint db_dir_path_len;
+
+ db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
+ db_name, "", "", 0);
+
+ if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
+ db_dir_path[db_dir_path_len - 1]= 0;
+
+ /* Check access. */
+
+ return my_access(db_dir_path, F_OK);
+}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 659695e8e73..df791e1f897 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -100,6 +100,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
/* Handler didn't support fast delete; Delete rows one by one */
}
+ if (conds)
+ {
+ Item::cond_result result;
+ conds= remove_eq_conds(thd, conds, &result);
+ if (result == Item::COND_FALSE) // Impossible where
+ limit= 0;
+ }
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (prune_partitions(thd, table, conds))
@@ -888,7 +895,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
}
path_length= build_table_filename(path, sizeof(path), table_list->db,
- table_list->table_name, reg_ext);
+ table_list->table_name, reg_ext, 0);
if (!dont_send_ok)
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e0164fa07be..5df6b1832f5 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2823,7 +2823,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
((thd->prelocked_mode == PRELOCKED) ?
MYSQL_OPEN_IGNORE_LOCKED_TABLES:0)))))
quick_rm_table(create_info->db_type, create_table->db,
- table_case_name(create_info, create_table->table_name));
+ table_case_name(create_info, create_table->table_name),
+ 0);
}
reenable_binlog(thd);
if (!table) // open failed
@@ -2845,7 +2846,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
hash_delete(&open_cache,(byte*) table);
VOID(pthread_mutex_unlock(&LOCK_open));
quick_rm_table(create_info->db_type, create_table->db,
- table_case_name(create_info, create_table->table_name));
+ table_case_name(create_info, create_table->table_name), 0);
DBUG_RETURN(0);
}
table->file->extra(HA_EXTRA_WRITE_CACHE);
@@ -3026,7 +3027,8 @@ void select_create::abort()
table->s->version= 0;
hash_delete(&open_cache,(byte*) table);
if (!create_info->table_existed)
- quick_rm_table(table_type, create_table->db, create_table->table_name);
+ quick_rm_table(table_type, create_table->db,
+ create_table->table_name, 0);
/* Tell threads waiting for refresh that something has happened */
if (version != refresh_version)
broadcast_refresh();
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index fe36b578f3b..bf0da9d46ef 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -127,6 +127,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->param_list.empty();
lex->view_list.empty();
lex->prepared_stmt_params.empty();
+ lex->auxiliary_table_list.empty();
lex->unit.next= lex->unit.master=
lex->unit.link_next= lex->unit.return_to= 0;
lex->unit.prev= lex->unit.link_prev= 0;
@@ -1060,6 +1061,30 @@ int MYSQLlex(void *arg, void *yythd)
}
}
+
+/*
+ Skip comment in the end of statement.
+
+ SYNOPSIS
+ skip_rear_comments()
+ begin pointer to the beginning of statement
+ end pointer to the end of statement
+
+ DESCRIPTION
+ The function is intended to trim comments at the end of the statement.
+
+ RETURN
+ Pointer to the last non-comment symbol of the statement.
+*/
+
+const uchar *skip_rear_comments(const uchar *begin, const uchar *end)
+{
+ while (begin < end && (end[-1] <= ' ' || end[-1] == '*' ||
+ end[-1] == '/' || end[-1] == ';'))
+ end-= 1;
+ return end;
+}
+
/*
st_select_lex structures initialisations
*/
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 5c0a88542b8..7e78a674b35 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -402,7 +402,7 @@ public:
friend class st_select_lex_unit;
friend bool mysql_new_select(struct st_lex *lex, bool move_down);
friend bool mysql_make_view(THD *thd, File_parser *parser,
- TABLE_LIST *table);
+ TABLE_LIST *table, uint flags);
private:
void fast_exclude();
};
@@ -1190,5 +1190,6 @@ extern void lex_free(void);
extern void lex_start(THD *thd, const uchar *buf, uint length);
extern void lex_end(LEX *lex);
extern int MYSQLlex(void *arg, void *yythd);
+extern const uchar *skip_rear_comments(const uchar *ubegin, const uchar *uend);
#endif /* MYSQL_SERVER */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b5154d60ed2..63de7bb1930 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4587,9 +4587,6 @@ end_with_restore_list:
}
else
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- Security_context *save_ctx;
-#endif
ha_rows select_limit;
/* bits that should be cleared in thd->server_status */
uint bits_to_be_cleared= 0;
@@ -4631,21 +4628,11 @@ end_with_restore_list:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, TRUE, 0) ||
- sp_change_security_context(thd, sp, &save_ctx))
+ sp->m_db.str, sp->m_name.str, TRUE, FALSE))
{
thd->net.no_send_ok= nsok;
goto error;
}
- if (save_ctx &&
- check_routine_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, TRUE, 0))
- {
- thd->net.no_send_ok= nsok;
- sp_restore_security_context(thd, save_ctx);
- goto error;
- }
-
#endif
select_limit= thd->variables.select_limit;
thd->variables.select_limit= HA_POS_ERROR;
@@ -4669,9 +4656,6 @@ end_with_restore_list:
thd->total_warn_count= 0;
thd->variables.select_limit= select_limit;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sp_restore_security_context(thd, save_ctx);
-#endif
thd->net.no_send_ok= nsok;
thd->server_status&= ~bits_to_be_cleared;
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 69a345bf2a4..49ca738ae7f 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -3441,7 +3441,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
char *src_db= table_ident->db.str ? table_ident->db.str : thd->db;
char *src_table= table_ident->table.str;
char buf[FN_REFLEN];
- build_table_filename(buf, sizeof(buf), src_db, src_table, "");
+ build_table_filename(buf, sizeof(buf), src_db, src_table, "", 0);
if (partition_default_handling(table, part_info,
FALSE, buf))
{
@@ -4715,7 +4715,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
handler *file= lpt->table->file;
DBUG_ENTER("mysql_change_partitions");
- build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "");
+ build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0);
if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied,
&lpt->deleted, lpt->pack_frm_data,
lpt->pack_frm_len)))
@@ -4755,7 +4755,7 @@ static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
int error;
DBUG_ENTER("mysql_rename_partitions");
- build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "");
+ build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0);
if ((error= lpt->table->file->rename_partitions(path)))
{
if (error != 1)
@@ -4796,7 +4796,7 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
int error;
DBUG_ENTER("mysql_drop_partitions");
- build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "");
+ build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0);
if ((error= lpt->table->file->drop_partitions(path)))
{
lpt->table->file->print_error(error, MYF(0));
@@ -5147,7 +5147,7 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
DBUG_ENTER("write_log_drop_shadow_frm");
build_table_filename(shadow_path, sizeof(shadow_path), lpt->db,
- lpt->table_name, "#");
+ lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_replace_delete_frm(lpt, 0UL, NULL,
(const char*)shadow_path, FALSE))
@@ -5195,9 +5195,9 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
part_info->first_log_entry= NULL;
build_table_filename(path, sizeof(path), lpt->db,
- lpt->table_name, "");
+ lpt->table_name, "", 0);
build_table_filename(shadow_path, sizeof(shadow_path), lpt->db,
- lpt->table_name, "#");
+ lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
goto error;
@@ -5249,9 +5249,9 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
part_info->first_log_entry= NULL;
build_table_filename(path, sizeof(path), lpt->db,
- lpt->table_name, "");
+ lpt->table_name, "", 0);
build_table_filename(tmp_path, sizeof(tmp_path), lpt->db,
- lpt->table_name, "#");
+ lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
@@ -5306,9 +5306,9 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
DBUG_ENTER("write_log_add_change_partition");
build_table_filename(path, sizeof(path), lpt->db,
- lpt->table_name, "");
+ lpt->table_name, "", 0);
build_table_filename(tmp_path, sizeof(tmp_path), lpt->db,
- lpt->table_name, "#");
+ lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
@@ -5363,9 +5363,9 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
part_info->first_log_entry= NULL;
build_table_filename(path, sizeof(path), lpt->db,
- lpt->table_name, "");
+ lpt->table_name, "", 0);
build_table_filename(shadow_path, sizeof(shadow_path), lpt->db,
- lpt->table_name, "#");
+ lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION))
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index ca31845ff95..16508516df7 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2134,29 +2134,21 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
they have their own table list).
*/
for (TABLE_LIST *tables= lex->query_tables;
- tables;
- tables= tables->next_global)
+ tables;
+ tables= tables->next_global)
+ {
+ tables->reinit_before_use(thd);
+ }
+ /*
+ Cleanup of the special case of DELETE t1, t2 FROM t1, t2, t3 ...
+ (multi-delete). We do a full clean up, although at the moment all we
+ need to clean in the tables of MULTI-DELETE list is 'table' member.
+ */
+ for (TABLE_LIST *tables= (TABLE_LIST*) lex->auxiliary_table_list.first;
+ tables;
+ tables= tables->next_global)
{
- /*
- Reset old pointers to TABLEs: they are not valid since the tables
- were closed in the end of previous prepare or execute call.
- */
tables->reinit_before_use(thd);
-
- /* Reset is_schema_table_processed value(needed for I_S tables */
- tables->is_schema_table_processed= FALSE;
-
- TABLE_LIST *embedded; /* The table at the current level of nesting. */
- TABLE_LIST *embedding= tables; /* The parent nested table reference. */
- do
- {
- embedded= embedding;
- if (embedded->prep_on_expr)
- embedded->on_expr= embedded->prep_on_expr->copy_andor_structure(thd);
- embedding= embedded->embedding;
- }
- while (embedding &&
- embedding->nested_join->join_list.head() == embedded);
}
lex->current_select= &lex->select_lex;
@@ -2171,7 +2163,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
}
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
- DBUG_VOID_RETURN;
+ DBUG_VOID_RETURN;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index e3468b2b5cf..73473ddd24b 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -157,14 +157,14 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
new_alias= new_table->table_name;
}
build_table_filename(name, sizeof(name),
- new_table->db, new_alias, reg_ext);
+ new_table->db, new_alias, reg_ext, 0);
if (!access(name,F_OK))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
DBUG_RETURN(ren_table); // This can't be skipped
}
build_table_filename(name, sizeof(name),
- ren_table->db, old_alias, reg_ext);
+ ren_table->db, old_alias, reg_ext, 0);
frm_type= mysql_frm_type(thd, name, &table_type);
switch (frm_type)
@@ -178,7 +178,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
if (!(rc= mysql_rename_table(ha_resolve_by_legacy_type(thd,
table_type),
ren_table->db, old_alias,
- new_table->db, new_alias)))
+ new_table->db, new_alias, 0)))
{
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
old_alias,
@@ -194,7 +194,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
(void) mysql_rename_table(ha_resolve_by_legacy_type(thd,
table_type),
new_table->db, new_alias,
- ren_table->db, old_alias);
+ ren_table->db, old_alias, 0);
}
}
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 530315b507b..eb6b37440ca 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -455,9 +455,35 @@ bool mysqld_show_column_types(THD *thd)
}
-int
-mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
- const char *wild, bool dir)
+/*
+ find_files() - find files in a given directory.
+
+ SYNOPSIS
+ find_files()
+ thd thread handler
+ files put found files in this list
+ db database name to set in TABLE_LIST structure
+ path path to database
+ wild filter for found files
+ dir read databases in path if TRUE, read .frm files in
+ database otherwise
+
+ RETURN
+ FIND_FILES_OK success
+ FIND_FILES_OOM out of memory error
+ FIND_FILES_DIR no such directory, or directory can't be read
+*/
+
+enum find_files_result {
+ FIND_FILES_OK,
+ FIND_FILES_OOM,
+ FIND_FILES_DIR
+};
+
+static
+find_files_result
+find_files(THD *thd, List<char> *files, const char *db,
+ const char *path, const char *wild, bool dir)
{
uint i;
char *ext;
@@ -467,8 +493,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
uint col_access=thd->col_access;
#endif
TABLE_LIST table_list;
- char tbbuff[FN_REFLEN];
- DBUG_ENTER("mysql_find_files");
+ DBUG_ENTER("find_files");
if (wild && !wild[0])
wild=0;
@@ -481,11 +506,9 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
else
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
- DBUG_RETURN(-1);
+ DBUG_RETURN(FIND_FILES_DIR);
}
- VOID(tablename_to_filename(tmp_file_prefix, tbbuff, sizeof(tbbuff)));
-
for (i=0 ; i < (uint) dirp->number_off_files ; i++)
{
char uname[NAME_LEN*3+1]; /* Unencoded name */
@@ -523,7 +546,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
{
// Return only .frm files which aren't temp files.
if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) ||
- is_prefix(file->name,tbbuff))
+ is_prefix(file->name, tmp_file_prefix))
continue;
*ext=0;
VOID(filename_to_tablename(file->name, uname, sizeof(uname)));
@@ -555,7 +578,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
if (files->push_back(thd->strdup(file->name)))
{
my_dirend(dirp);
- DBUG_RETURN(-1);
+ DBUG_RETURN(FIND_FILES_OOM);
}
}
DBUG_PRINT("info",("found: %d files", files->elements));
@@ -563,7 +586,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
VOID(ha_find_files(thd,db,path,wild,dir,files));
- DBUG_RETURN(0);
+ DBUG_RETURN(FIND_FILES_OK);
}
@@ -657,13 +680,11 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
{
Security_context *sctx= thd->security_ctx;
int length;
- char path[FN_REFLEN];
char buff[2048];
String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint db_access;
#endif
- bool found_libchar;
HA_CREATE_INFO create;
uint create_options = create_info ? create_info->options : 0;
Protocol *protocol=thd->protocol;
@@ -692,22 +713,13 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
}
else
{
- length= build_table_filename(path, sizeof(path), dbname, "", "");
- found_libchar= 0;
- if (length && path[length-1] == FN_LIBCHAR)
- {
- found_libchar= 1;
- path[length-1]=0; // remove ending '\'
- }
- if (access(path,F_OK))
+ if (check_db_dir_existence(dbname))
{
my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
DBUG_RETURN(TRUE);
}
- if (found_libchar)
- path[length-1]= FN_LIBCHAR;
- strmov(path+length, MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
+
+ load_db_opt_by_name(thd, dbname, &create);
}
List<Item> field_list;
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
@@ -2356,8 +2368,8 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
wild string otherwise it's db name;
RETURN
- 1 error
- 0 success
+ zero success
+ non-zero error
*/
int make_db_list(THD *thd, List<char> *files,
@@ -2383,8 +2395,8 @@ int make_db_list(THD *thd, List<char> *files,
if (files->push_back(thd->strdup(information_schema_name.str)))
return 1;
}
- return mysql_find_files(thd, files, NullS, mysql_data_home,
- idx_field_vals->db_value, 1);
+ return (find_files(thd, files, NullS, mysql_data_home,
+ idx_field_vals->db_value, 1) != FIND_FILES_OK);
}
/*
@@ -2410,7 +2422,8 @@ int make_db_list(THD *thd, List<char> *files,
if (files->push_back(thd->strdup(information_schema_name.str)))
return 1;
*with_i_schema= 1;
- return mysql_find_files(thd, files, NullS, mysql_data_home, NullS, 1);
+ return (find_files(thd, files, NullS,
+ mysql_data_home, NullS, 1) != FIND_FILES_OK);
}
@@ -2558,12 +2571,31 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- len= build_table_filename(path, sizeof(path), base_name, "", "");
+ len= build_table_filename(path, sizeof(path), base_name, "", "", 0);
end= path + len;
len= FN_LEN - len;
- if (mysql_find_files(thd, &files, base_name,
- path, idx_field_vals.table_value, 0))
- goto err;
+ find_files_result res= find_files(thd, &files, base_name,
+ path, idx_field_vals.table_value, 0);
+ if (res != FIND_FILES_OK)
+ {
+ /*
+ Downgrade errors about problems with database directory to
+ warnings if this is not a 'SHOW' command. Another thread
+ may have dropped database, and we may still have a name
+ for that directory.
+ */
+ if (res == FIND_FILES_DIR && lex->sql_command == SQLCOM_END)
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ continue;
+ }
+ else
+ {
+ goto err;
+ }
+ }
if (lower_case_table_names)
orig_base_name= thd->strdup(base_name);
}
@@ -2679,8 +2711,11 @@ bool store_schema_shemata(THD* thd, TABLE *table, const char *db_name,
int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
{
- char path[FN_REFLEN];
- bool found_libchar;
+ /*
+ TODO: fill_schema_shemata() is called when new client is connected.
+ Returning error status in this case leads to client hangup.
+ */
+
INDEX_FIELD_VALUES idx_field_vals;
List<char> files;
char *file_name;
@@ -2712,19 +2747,9 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
(grant_option && !check_grant_db(thd, file_name)))
#endif
{
- length= build_table_filename(path, sizeof(path), file_name, "", "");
- found_libchar= 0;
- if (length && path[length-1] == FN_LIBCHAR)
- {
- found_libchar= 1;
- path[length-1]=0; // remove ending '\'
- }
+ load_db_opt_by_name(thd, file_name, &create);
- if (found_libchar)
- path[length-1]= FN_LIBCHAR;
- strmov(path+length, MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
- if (store_schema_shemata(thd, table, file_name,
+ if (store_schema_shemata(thd, table, file_name,
create.default_table_charset))
DBUG_RETURN(1);
}
@@ -5114,7 +5139,12 @@ bool get_schema_tables_result(JOIN *join)
if (table_list->schema_table->fill_table(thd, table_list,
tab->select_cond))
+ {
result= 1;
+ join->error= 1;
+ table_list->is_schema_table_processed= TRUE;
+ break;
+ }
table_list->is_schema_table_processed= TRUE;
}
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5325758fd12..f0f69676ed2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -51,31 +51,77 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
#define MYSQL50_TABLE_NAME_PREFIX "#mysql50#"
#define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9
+
+/*
+ Translate a file name to a table name (WL #1324).
+
+ SYNOPSIS
+ filename_to_tablename()
+ from The file name in my_charset_filename.
+ to OUT The table name in system_charset_info.
+ to_length The size of the table name buffer.
+
+ RETURN
+ Table name length.
+*/
+
uint filename_to_tablename(const char *from, char *to, uint to_length)
{
- uint errors, res= strconvert(&my_charset_filename, from,
- system_charset_info, to, to_length, &errors);
- if (errors) // Old 5.0 name
+ uint errors;
+ uint res;
+ DBUG_ENTER("filename_to_tablename");
+ DBUG_PRINT("enter", ("from '%s'", from));
+
+ if (!memcmp(from, tmp_file_prefix, tmp_file_prefix_length))
{
- res= strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) - to;
- sql_print_error("Invalid (old?) table or database name '%s'", from);
- /*
- TODO: add a stored procedure for fix table and database names,
- and mention its name in error log.
- */
+ /* Temporary table name. */
+ res= (strnmov(to, from, to_length) - to);
+ }
+ else
+ {
+ res= strconvert(&my_charset_filename, from,
+ system_charset_info, to, to_length, &errors);
+ if (errors) // Old 5.0 name
+ {
+ res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) -
+ to);
+ sql_print_error("Invalid (old?) table or database name '%s'", from);
+ /*
+ TODO: add a stored procedure for fix table and database names,
+ and mention its name in error log.
+ */
+ }
}
- return res;
+
+ DBUG_PRINT("exit", ("to '%s'", to));
+ DBUG_RETURN(res);
}
+/*
+ Translate a table name to a file name (WL #1324).
+
+ SYNOPSIS
+ tablename_to_filename()
+ from The table name in system_charset_info.
+ to OUT The file name in my_charset_filename.
+ to_length The size of the file name buffer.
+
+ RETURN
+ File name length.
+*/
+
uint tablename_to_filename(const char *from, char *to, uint to_length)
{
uint errors, length;
+ DBUG_ENTER("tablename_to_filename");
+ DBUG_PRINT("enter", ("from '%s'", from));
+
if (from[0] == '#' && !strncmp(from, MYSQL50_TABLE_NAME_PREFIX,
MYSQL50_TABLE_NAME_PREFIX_LENGTH))
- return (uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH,
- to_length-1) -
- (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH));
+ DBUG_RETURN((uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH,
+ to_length-1) -
+ (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH)));
length= strconvert(system_charset_info, from,
&my_charset_filename, to, to_length, &errors);
if (check_if_legal_tablename(to) &&
@@ -84,7 +130,8 @@ uint tablename_to_filename(const char *from, char *to, uint to_length)
memcpy(to + length, "@@@", 4);
length+= 3;
}
- return length;
+ DBUG_PRINT("exit", ("to '%s'", to));
+ DBUG_RETURN(length);
}
@@ -93,52 +140,87 @@ uint tablename_to_filename(const char *from, char *to, uint to_length)
SYNOPSIS
build_table_filename()
- buff where to write result
- bufflen buff size
- db database name, in system_charset_info
- table table name, in system_charset_info
- ext file extension
+ buff Where to write result in my_charset_filename.
+ bufflen buff size
+ db Database name in system_charset_info.
+ table_name Table name in system_charset_info.
+ ext File extension.
+ flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP
+ table_name is temporary, do not change.
NOTES
Uses database and table name, and extension to create
a file name in mysql_data_dir. Database and table
names are converted from system_charset_info into "fscs".
+ Unless flags indicate a temporary table name.
+ 'db' is always converted.
'ext' is not converted.
- RETURN
+ The conversion suppression is required for ALTER TABLE. This
+ statement creates intermediate tables. These are regular
+ (non-temporary) tables with a temporary name. Their path names must
+ be derivable from the table name. So we cannot use
+ build_tmptable_filename() for them.
+ RETURN
+ path length
*/
-
uint build_table_filename(char *buff, size_t bufflen, const char *db,
- const char *table, const char *ext)
+ const char *table_name, const char *ext, uint flags)
{
uint length;
char dbbuff[FN_REFLEN];
char tbbuff[FN_REFLEN];
- VOID(tablename_to_filename(table, tbbuff, sizeof(tbbuff)));
+ DBUG_ENTER("build_table_filename");
+
+ if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
+ strnmov(tbbuff, table_name, sizeof(tbbuff));
+ else
+ VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff)));
+
VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff)));
- strxnmov(buff, bufflen,
- mysql_data_home, "/", dbbuff, "/", tbbuff, ext, NullS);
- length= unpack_filename(buff, buff);
- return length;
+ length= strxnmov(buff, bufflen, mysql_data_home, "/", dbbuff,
+ "/", tbbuff, ext, NullS) - buff;
+ DBUG_PRINT("exit", ("buff: '%s'", buff));
+ DBUG_RETURN(length);
}
+/*
+ Creates path to a file: mysql_tmpdir/#sql1234_12_1.ext
+
+ SYNOPSIS
+ build_tmptable_filename()
+ thd The thread handle.
+ buff Where to write result in my_charset_filename.
+ bufflen buff size
+
+ NOTES
+
+ Uses current_pid, thread_id, and tmp_table counter to create
+ a file name in mysql_tmpdir.
+
+ RETURN
+ path length
+*/
+
uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
{
uint length;
- char tbbuff[FN_REFLEN];
char tmp_table_name[tmp_file_prefix_length+22+22+22+3];
+ DBUG_ENTER("build_tmptable_filename");
+
my_snprintf(tmp_table_name, sizeof(tmp_table_name),
"%s%lx_%lx_%x",
tmp_file_prefix, current_pid,
thd->thread_id, thd->tmp_table++);
- VOID(tablename_to_filename(tmp_table_name, tbbuff, sizeof(tbbuff)));
- strxnmov(buff, bufflen, mysql_tmpdir, "/", tbbuff, reg_ext, NullS);
+
+ strxnmov(buff, bufflen, mysql_tmpdir, "/", tmp_table_name, reg_ext, NullS);
length= unpack_filename(buff, buff);
- return length;
+ DBUG_PRINT("exit", ("buff: '%s'", buff));
+ DBUG_RETURN(length);
}
/*
@@ -1201,7 +1283,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
Build shadow frm file name
*/
build_table_filename(shadow_path, sizeof(shadow_path), lpt->db,
- lpt->table_name, "#");
+ lpt->table_name, "#", 0);
strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
if (flags & WFRM_WRITE_SHADOW)
{
@@ -1285,7 +1367,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
Build frm file name
*/
build_table_filename(path, sizeof(path), lpt->db,
- lpt->table_name, "");
+ lpt->table_name, "", 0);
strxmov(frm_name, path, reg_ext, NullS);
/*
When we are changing to use new frm file we need to ensure that we
@@ -1618,7 +1700,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove .frm file and engine files */
path_length= build_table_filename(path, sizeof(path),
- db, alias, reg_ext);
+ db, alias, reg_ext, 0);
}
if (drop_temporary ||
(table_type == NULL &&
@@ -1742,15 +1824,30 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
+/*
+ Quickly remove a table.
+
+ SYNOPSIS
+ quick_rm_table()
+ base The handlerton handle.
+ db The database name.
+ table_name The table name.
+ flags flags for build_table_filename().
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
bool quick_rm_table(handlerton *base,const char *db,
- const char *table_name)
+ const char *table_name, uint flags)
{
char path[FN_REFLEN];
bool error= 0;
DBUG_ENTER("quick_rm_table");
uint path_length= build_table_filename(path, sizeof(path),
- db, table_name, reg_ext);
+ db, table_name, reg_ext, flags);
if (my_delete(path,MYF(0)))
error= 1; /* purecov: inspected */
path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
@@ -2896,13 +2993,17 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
static void set_table_default_charset(THD *thd,
HA_CREATE_INFO *create_info, char *db)
{
+ /*
+ If the table character set was not given explicitly,
+ let's fetch the database default character set and
+ apply it to the table.
+ */
if (!create_info->default_table_charset)
{
HA_CREATE_INFO db_info;
- char path[FN_REFLEN];
- /* Abuse build_table_filename() to build the path to the db.opt file */
- build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE);
- load_db_opt(thd, path, &db_info);
+
+ load_db_opt_by_name(thd, db, &db_info);
+
create_info->default_table_charset= db_info.default_table_charset;
}
}
@@ -3084,6 +3185,8 @@ bool mysql_create_table_internal(THD *thd,
handler *file;
bool error= TRUE;
DBUG_ENTER("mysql_create_table_internal");
+ DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
+ db, table_name, internal_tmp_table));
if (use_copy_create_info)
{
@@ -3303,7 +3406,8 @@ bool mysql_create_table_internal(THD *thd,
start++;
}
#endif
- path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext);
+ path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
+ internal_tmp_table ? FN_IS_TMP : 0);
}
/* Check if table already exists */
@@ -3513,12 +3617,30 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end)
** Alter a table definition
****************************************************************************/
+
+/*
+ Rename a table.
+
+ SYNOPSIS
+ mysql_rename_table()
+ base The handlerton handle.
+ old_db The old database name.
+ old_name The old table name.
+ new_db The new database name.
+ new_name The new table name.
+ flags flags for build_table_filename().
+ FN_FROM_IS_TMP old_name is temporary.
+ FN_TO_IS_TMP new_name is temporary.
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
bool
-mysql_rename_table(handlerton *base,
- const char *old_db,
- const char *old_name,
- const char *new_db,
- const char *new_name)
+mysql_rename_table(handlerton *base, const char *old_db,
+ const char *old_name, const char *new_db,
+ const char *new_name, uint flags)
{
THD *thd= current_thd;
char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN];
@@ -3527,12 +3649,16 @@ mysql_rename_table(handlerton *base,
handler *file;
int error=0;
DBUG_ENTER("mysql_rename_table");
+ DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'",
+ old_db, old_name, new_db, new_name));
file= (base == NULL ? 0 :
get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
- build_table_filename(from, sizeof(from), old_db, old_name, "");
- build_table_filename(to, sizeof(to), new_db, new_name, "");
+ build_table_filename(from, sizeof(from), old_db, old_name, "",
+ flags & FN_FROM_IS_TMP);
+ build_table_filename(to, sizeof(to), new_db, new_name, "",
+ flags & FN_TO_IS_TMP);
/*
If lower_case_table_names == 2 (case-preserving but case-insensitive
@@ -3544,12 +3670,14 @@ mysql_rename_table(handlerton *base,
{
strmov(tmp_name, old_name);
my_casedn_str(files_charset_info, tmp_name);
- build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "");
+ build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "",
+ flags & FN_FROM_IS_TMP);
from_base= lc_from;
strmov(tmp_name, new_name);
my_casedn_str(files_charset_info, tmp_name);
- build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "");
+ build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "",
+ flags & FN_TO_IS_TMP);
to_base= lc_to;
}
@@ -3685,7 +3813,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
if (fn_format_relative_to_data_home(src_path, uname, backup_dir, reg_ext))
DBUG_RETURN(-1); // protect buffer overflow
- build_table_filename(dst_path, sizeof(dst_path), db, table_name, reg_ext);
+ build_table_filename(dst_path, sizeof(dst_path),
+ db, table_name, reg_ext, 0);
if (lock_and_wait_for_table_name(thd,table))
DBUG_RETURN(-1);
@@ -3762,6 +3891,15 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
table= &tmp_table;
pthread_mutex_unlock(&LOCK_open);
}
+ /*
+ REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
+ */
+ if (table->s->tmp_table)
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Cannot repair temporary table from .frm file");
+ goto end;
+ }
/*
User gave us USE_FRM which means that the header in the index file is
@@ -4459,7 +4597,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
else
{
build_table_filename(src_path, sizeof(src_path),
- src_db, src_table, reg_ext);
+ src_db, src_table, reg_ext, 0);
/* Resolve symlinks (for windows) */
unpack_filename(src_path, src_path);
if (lower_case_table_names)
@@ -4498,7 +4636,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
else
{
dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
- db, table_name, reg_ext);
+ db, table_name, reg_ext, 0);
if (!access(dst_path, F_OK))
goto table_exists;
}
@@ -4548,7 +4686,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
else if (err)
{
(void) quick_rm_table(create_info->db_type, db,
- table_name); /* purecov: inspected */
+ table_name, 0); /* purecov: inspected */
goto err; /* purecov: inspected */
}
@@ -5062,8 +5200,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
db=table_list->db;
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
new_db= db;
- build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext);
- build_table_filename(path, sizeof(path), db, table_name, "");
+ build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0);
+ build_table_filename(path, sizeof(path), db, table_name, "", 0);
used_fields=create_info->used_fields;
@@ -5080,6 +5218,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* Check that we are not trying to rename to an existing table */
if (new_name)
{
+ DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name));
strmov(new_name_buff,new_name);
strmov(new_alias= new_alias_buff, new_name);
if (lower_case_table_names)
@@ -5112,11 +5251,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
else
{
- char dir_buff[FN_REFLEN];
- strxnmov(dir_buff, sizeof(dir_buff)-1,
- mysql_real_data_home, new_db, NullS);
- if (!access(fn_format(new_name_buff,new_name_buff,dir_buff,reg_ext,0),
- F_OK))
+ build_table_filename(new_name_buff, sizeof(new_name_buff),
+ new_db, new_name_buff, reg_ext, 0);
+ if (!access(new_name_buff, F_OK))
{
/* Table will be closed in do_command() */
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
@@ -5197,13 +5334,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
*fn_ext(new_name)=0;
table->s->version= 0; // Force removal of table def
close_cached_table(thd, table);
- if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias))
+ if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
error= -1;
else if (Table_triggers_list::change_table_name(thd, db, table_name,
new_db, new_alias))
{
VOID(mysql_rename_table(old_db_type, new_db, new_alias, db,
- table_name));
+ table_name, 0));
error= -1;
}
}
@@ -5834,7 +5971,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
char path[FN_REFLEN];
/* table is a normal table: Create temporary table in same directory */
- build_table_filename(path, sizeof(path), new_db, tmp_name, "");
+ build_table_filename(path, sizeof(path), new_db, tmp_name, "",
+ FN_IS_TMP);
new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
}
if (!new_table)
@@ -6047,7 +6185,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
VOID(pthread_mutex_lock(&LOCK_open));
if (error)
{
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
@@ -6069,7 +6207,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
error=1;
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
@@ -6097,22 +6235,24 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error=0;
if (!need_copy_table)
new_db_type=old_db_type= NULL; // this type cannot happen in regular ALTER
- if (mysql_rename_table(old_db_type,db,table_name,db,old_name))
+ if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
+ FN_TO_IS_TMP))
{
error=1;
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
}
else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db,
- new_alias) ||
+ new_alias, FN_FROM_IS_TMP) ||
(new_name != table_name || new_db != db) && // we also do rename
Table_triggers_list::change_table_name(thd, db, table_name,
new_db, new_alias))
-
- { // Try to get everything back
+ {
+ /* Try to get everything back. */
error=1;
- VOID(quick_rm_table(new_db_type,new_db,new_alias));
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
- VOID(mysql_rename_table(old_db_type,db,old_name,db,alias));
+ VOID(quick_rm_table(new_db_type,new_db,new_alias, 0));
+ VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
+ VOID(mysql_rename_table(old_db_type, db, old_name, db, alias,
+ FN_FROM_IS_TMP));
}
if (error)
{
@@ -6156,7 +6296,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
table->s->version= 0; // Force removal of table def
close_cached_table(thd,table);
}
- VOID(quick_rm_table(old_db_type,db,old_name));
+ VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
}
else
{
@@ -6173,7 +6313,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* end threads waiting on lock */
mysql_lock_abort(thd,table, TRUE);
}
- VOID(quick_rm_table(old_db_type,db,old_name));
+ VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
if (close_data_tables(thd,db,table_name) ||
reopen_tables(thd,1,0))
{ // This shouldn't happen
@@ -6223,7 +6363,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
shutdown.
*/
char path[FN_REFLEN];
- build_table_filename(path, sizeof(path), new_db, table_name, "");
+ build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
table=open_temporary_table(thd, path, new_db, tmp_name,0);
if (table)
{
@@ -6254,7 +6394,7 @@ end_temporary:
close_temporary_table(thd, new_table, 1, 1);
}
else
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
err:
DBUG_RETURN(TRUE);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index e990b7bc86d..a49e9d67a00 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -301,7 +301,10 @@ end:
append_definer(thd, &log_query, &definer_user, &definer_host);
}
- log_query.append(thd->lex->stmt_definition_begin);
+ log_query.append(thd->lex->stmt_definition_begin,
+ (char *)thd->lex->sphead->m_body_begin -
+ thd->lex->stmt_definition_begin +
+ thd->lex->sphead->m_body.length);
}
/* Such a statement can always go directly to binlog, no trans cache. */
@@ -468,12 +471,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
*/
file.length= build_table_filename(file_buff, FN_REFLEN-1,
tables->db, tables->table_name,
- triggers_file_ext);
+ triggers_file_ext, 0);
file.str= file_buff;
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
tables->db,
lex->spname->m_name.str,
- trigname_file_ext);
+ trigname_file_ext, 0);
trigname_file.str= trigname_buff;
/* Use the filesystem to enforce trigger namespace constraints. */
@@ -579,7 +582,7 @@ err_with_cleanup:
static bool rm_trigger_file(char *path, const char *db,
const char *table_name)
{
- build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext);
+ build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext, 0);
return my_delete(path, MYF(MY_WME));
}
@@ -602,7 +605,8 @@ static bool rm_trigger_file(char *path, const char *db,
static bool rm_trigname_file(char *path, const char *db,
const char *trigger_name)
{
- build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext);
+ build_table_filename(path, FN_REFLEN-1,
+ db, trigger_name, trigname_file_ext, 0);
return my_delete(path, MYF(MY_WME));
}
@@ -628,7 +632,7 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
LEX_STRING file;
file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name,
- triggers_file_ext);
+ triggers_file_ext, 0);
file.str= file_buff;
return sql_create_definition_file(NULL, &file, &triggers_file_type,
(gptr)triggers, triggers_file_parameters,
@@ -803,7 +807,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
DBUG_ENTER("Table_triggers_list::check_n_load");
path.length= build_table_filename(path_buff, FN_REFLEN-1,
- db, table_name, triggers_file_ext);
+ db, table_name, triggers_file_ext, 0);
path.str= path_buff;
// QQ: should we analyze errno somehow ?
@@ -1159,7 +1163,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
path.length= build_table_filename(path_buff, FN_REFLEN-1,
trig->m_db.str, trig->m_name.str,
- trigname_file_ext);
+ trigname_file_ext, 0);
path.str= path_buff;
if (access(path_buff, F_OK))
@@ -1366,7 +1370,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name,
{
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
db_name, trigger->str,
- trigname_file_ext);
+ trigname_file_ext, 0);
trigname_file.str= trigname_buff;
trigname.trigger_table= *new_table_name;
@@ -1496,7 +1500,6 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
new_field= record1_field;
old_field= table->field;
}
-
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_ctx;
@@ -1530,7 +1533,9 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
#endif // NO_EMBEDDED_ACCESS_CHECKS
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
- err_status= sp_trigger->execute_function(thd, 0, 0, 0);
+ err_status= sp_trigger->execute_trigger
+ (thd, table->s->db.str, table->s->table_name.str,
+ &subject_table_grants[event][time_type]);
thd->restore_sub_statement_state(&statement_state);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 13302c2c3f7..f0d31965573 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -210,7 +210,7 @@ void udf_init()
}
}
if (error > 0)
- sql_print_error(ER(ER_GET_ERRNO), my_errno);
+ sql_print_error("Got unknown error: %d", my_errno);
end_read_record(&read_record_info);
new_thd->version--; // Force close to free memory
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 66258fca945..241e47f10d9 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -183,11 +183,13 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
TABLE_LIST decoy;
memcpy (&decoy, view, sizeof (TABLE_LIST));
- if (!open_table(thd, &decoy, thd->mem_root, &not_used, 0) &&
+ if (!open_table(thd, &decoy, thd->mem_root, &not_used, OPEN_VIEW_NO_PARSE) &&
!decoy.view)
{
+ /* It's a table */
return TRUE;
}
+
if (!lex->definer)
{
view->definer.host= decoy.definer.host;
@@ -646,6 +648,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
char md5[MD5_BUFF_LENGTH];
bool can_be_merged;
char dir_buff[FN_REFLEN], file_buff[FN_REFLEN], path_buff[FN_REFLEN];
+ const uchar *endp;
LEX_STRING dir, file, path;
DBUG_ENTER("mysql_register_view");
@@ -662,11 +665,11 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
/* print file name */
dir.length= build_table_filename(dir_buff, sizeof(dir_buff),
- view->db, "", "");
+ view->db, "", "", 0);
dir.str= dir_buff;
path.length= build_table_filename(path_buff, sizeof(path_buff),
- view->db, view->table_name, reg_ext);
+ view->db, view->table_name, reg_ext, 0);
path.str= path_buff;
file.str= path.str + dir.length;
@@ -729,8 +732,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
view->query.str= (char*)str.ptr();
view->query.length= str.length()-1; // we do not need last \0
view->source.str= thd->query + thd->lex->create_view_select_start;
- view->source.length= (thd->query_length -
- thd->lex->create_view_select_start);
+ endp= (uchar*) view->source.str;
+ endp= skip_rear_comments(endp, (uchar*) (thd->query + thd->query_length));
+ view->source.length= endp - (uchar*) view->source.str;
view->file_version= 1;
view->calc_md5(md5);
view->md5.str= md5;
@@ -817,13 +821,14 @@ loop_out:
thd Thread handler
parser parser object
table TABLE_LIST structure for filling
-
+ flags flags
RETURN
0 ok
1 error
*/
-bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
+bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
+ uint flags)
{
SELECT_LEX *end, *view_select;
LEX *old_lex, *lex;
@@ -914,6 +919,10 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
table->db, table->table_name);
get_default_definer(thd, &table->definer);
}
+ if (flags & OPEN_VIEW_NO_PARSE)
+ {
+ DBUG_RETURN(FALSE);
+ }
/*
Save VIEW parameters, which will be wiped out by derived table
@@ -1306,7 +1315,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
TABLE_SHARE *share;
frm_type_enum type= FRMTYPE_ERROR;
build_table_filename(path, sizeof(path),
- view->db, view->table_name, reg_ext);
+ view->db, view->table_name, reg_ext, 0);
VOID(pthread_mutex_lock(&LOCK_open));
if (access(path, F_OK) ||
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 1e3e5f4aa73..7e54d57cfdf 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -19,7 +19,8 @@
bool mysql_create_view(THD *thd,
enum_view_create_mode mode);
-bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table);
+bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
+ uint flags);
bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4fd4572e58b..ba4c652efb7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1530,7 +1530,7 @@ ev_sql_stmt:
{
sp_head *sp= lex->sphead;
// return back to the original memory root ASAP
- sp->init_strings(YYTHD, lex, NULL);
+ sp->init_strings(YYTHD, lex);
sp->restore_thd_mem_root(YYTHD);
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
@@ -1613,6 +1613,17 @@ create_function_tail:
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
LEX *lex=Lex;
+ if (lex->definer != NULL)
+ {
+ /*
+ DEFINER is a concept meaningful when interpreting SQL code.
+ UDF functions are compiled.
+ Using DEFINER with UDF has therefore no semantic,
+ and is considered a parsing error.
+ */
+ my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
+ YYABORT;
+ }
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
lex->udf.returns=(Item_result) $2;
@@ -1642,6 +1653,7 @@ create_function_tail:
sp= new sp_head();
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
+ sp->init_sp_name(YYTHD, lex->spname);
sp->m_type= TYPE_ENUM_FUNCTION;
lex->sphead= sp;
@@ -1707,7 +1719,7 @@ create_function_tail:
YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
- sp->init_strings(YYTHD, lex, lex->spname);
+ sp->init_strings(YYTHD, lex);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
@@ -2302,9 +2314,12 @@ sp_proc_stmt_statement:
sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
lex->spcont, lex);
- /* Extract the query statement from the tokenizer:
- The end is either lex->tok_end or tok->ptr. */
- if (lex->ptr - lex->tok_end > 1)
+ /*
+ Extract the query statement from the tokenizer. The
+ end is either lex->ptr, if there was no lookahead,
+ lex->tok_end otherwise.
+ */
+ if (yychar == YYEMPTY)
i->m_query.length= lex->ptr - sp->m_tmp_query;
else
i->m_query.length= lex->tok_end - sp->m_tmp_query;
@@ -4457,7 +4472,7 @@ opt_bin_mod:
| BINARY { Lex->type|= BINCMP_FLAG; };
opt_bin_charset:
- /* empty */ { }
+ /* empty */ { Lex->charset= NULL; }
| ASCII_SYM { Lex->charset=&my_charset_latin1; }
| UNICODE_SYM
{
@@ -9331,7 +9346,6 @@ user:
keyword:
keyword_sp {}
| ASCII_SYM {}
- | AUTHORS_SYM {}
| BACKUP_SYM {}
| BEGIN_SYM {}
| BYTE_SYM {}
@@ -9389,6 +9403,7 @@ keyword_sp:
| ALGORITHM_SYM {}
| ANY_SYM {}
| AT_SYM {}
+ | AUTHORS_SYM {}
| AUTO_INC {}
| AUTOEXTEND_SIZE_SYM {}
| AVG_ROW_LENGTH {}
@@ -9414,6 +9429,7 @@ keyword_sp:
| COMPRESSED_SYM {}
| CONCURRENT {}
| CONSISTENT_SYM {}
+ | CONTRIBUTORS_SYM {}
| CUBE_SYM {}
| DATA_SYM {}
| DATAFILE_SYM {}
@@ -9701,7 +9717,12 @@ option_type_value:
lex)))
YYABORT;
- if (lex->ptr - lex->tok_end > 1)
+ /*
+ Extract the query statement from the tokenizer. The
+ end is either lex->ptr, if there was no lookahead,
+ lex->tok_end otherwise.
+ */
+ if (yychar == YYEMPTY)
qbuff.length= lex->ptr - sp->m_tmp_query;
else
qbuff.length= lex->tok_end - sp->m_tmp_query;
@@ -10972,7 +10993,7 @@ trigger_tail:
YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
-
+ sp->init_sp_name(YYTHD, $3);
lex->stmt_definition_begin= $2;
lex->ident.str= $7;
lex->ident.length= $10 - $7;
@@ -11000,7 +11021,7 @@ trigger_tail:
sp_head *sp= lex->sphead;
lex->sql_command= SQLCOM_CREATE_TRIGGER;
- sp->init_strings(YYTHD, lex, $3);
+ sp->init_strings(YYTHD, lex);
/* Restore flag if it was cleared above */
YYTHD->client_capabilities |= $<ulong_num>13;
@@ -11048,13 +11069,14 @@ sp_tail:
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
YYABORT;
}
-
+
lex->stmt_definition_begin= $2;
-
+
/* Order is important here: new - reset - init */
sp= new sp_head();
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
+ sp->init_sp_name(YYTHD, $3);
sp->m_type= TYPE_ENUM_PROCEDURE;
lex->sphead= sp;
@@ -11092,7 +11114,7 @@ sp_tail:
LEX *lex= Lex;
sp_head *sp= lex->sphead;
- sp->init_strings(YYTHD, lex, $3);
+ sp->init_strings(YYTHD, lex);
lex->sql_command= SQLCOM_CREATE_PROCEDURE;
/*
Restore flag if it was cleared above
diff --git a/sql/table.cc b/sql/table.cc
index 71d4f8df837..f0a864287b0 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -68,7 +68,7 @@ static byte *get_field_name(Field **buff, uint *length,
char *fn_rext(char *name)
{
char *res= strrchr(name, '.');
- if (res && !strcmp(res, ".frm"))
+ if (res && !strcmp(res, reg_ext))
return res;
return name + strlen(name);
}
@@ -95,10 +95,13 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
TABLE_SHARE *share;
char path[FN_REFLEN];
uint path_length;
+ DBUG_ENTER("alloc_table_share");
+ DBUG_PRINT("enter", ("table: '%s'.'%s'",
+ table_list->db, table_list->table_name));
path_length= build_table_filename(path, sizeof(path) - 1,
table_list->db,
- table_list->table_name, "");
+ table_list->table_name, "", 0);
init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
if ((share= (TABLE_SHARE*) alloc_root(&mem_root,
sizeof(*share) + key_length +
@@ -148,7 +151,7 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
pthread_cond_init(&share->cond, NULL);
}
- return share;
+ DBUG_RETURN(share);
}
@@ -179,6 +182,7 @@ void init_tmp_table_share(TABLE_SHARE *share, const char *key,
const char *path)
{
DBUG_ENTER("init_tmp_table_share");
+ DBUG_PRINT("enter", ("table: '%s'.'%s'", key, table_name));
bzero((char*) share, sizeof(*share));
init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
@@ -286,7 +290,8 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
char path[FN_REFLEN];
MEM_ROOT **root_ptr, *old_root;
DBUG_ENTER("open_table_def");
- DBUG_PRINT("enter", ("name: '%s.%s'",share->db.str, share->table_name.str));
+ DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str,
+ share->table_name.str, share->normalized_path.str));
error= 1;
error_given= 0;
@@ -352,7 +357,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
}
else
goto err;
-
+
/* No handling of text based files yet */
if (table_type == 1)
{
@@ -4041,13 +4046,27 @@ void st_table::mark_columns_needed_for_insert()
st_table_list::reinit_before_use()
*/
-void st_table_list::reinit_before_use(THD * /* thd */)
+void st_table_list::reinit_before_use(THD *thd)
{
/*
Reset old pointers to TABLEs: they are not valid since the tables
were closed in the end of previous prepare or execute call.
*/
table= 0;
+ /* Reset is_schema_table_processed value(needed for I_S tables */
+ is_schema_table_processed= FALSE;
+
+ TABLE_LIST *embedded; /* The table at the current level of nesting. */
+ TABLE_LIST *embedding= this; /* The parent nested table reference. */
+ do
+ {
+ embedded= embedding;
+ if (embedded->prep_on_expr)
+ embedded->on_expr= embedded->prep_on_expr->copy_andor_structure(thd);
+ embedding= embedded->embedding;
+ }
+ while (embedding &&
+ embedding->nested_join->join_list.head() == embedded);
}
diff --git a/sql/table.h b/sql/table.h
index 0d8ec4f98e1..7675c27823b 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -795,6 +795,10 @@ typedef struct st_table_list
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
+ /*
+ Cleanup for re-execution in a prepared statement or a stored
+ procedure.
+ */
} TABLE_LIST;
class Item;
diff --git a/sql/udf_example.c b/sql/udf_example.c
index 62995085599..a80fce81278 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -806,6 +806,7 @@ char *reverse_lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
char name_buff[256];
struct hostent tmp_hostent;
+ int tmp_errno;
#endif
struct hostent *hp;
unsigned long taddr;
@@ -845,7 +846,6 @@ char *reverse_lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
return 0;
}
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
- int tmp_errno;
if (!(hp=gethostbyaddr_r((char*) &taddr,sizeof(taddr), AF_INET,
&tmp_hostent, name_buff,sizeof(name_buff),
&tmp_errno)))
diff --git a/sql/unireg.h b/sql/unireg.h
index 9ab8753af84..af91793e8fe 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -151,7 +151,8 @@
#define READ_SCREENS 1024 /* Read screens, info and helpfile */
#define DELAYED_OPEN 4096 /* Open table later */
#define OPEN_VIEW 8192 /* Allow open on view */
-
+#define OPEN_VIEW_NO_PARSE 16384 /* Open frm only if it's a view,
+ but do not parse view itself */
#define SC_INFO_LENGTH 4 /* Form format constant */
#define TE_INFO_LENGTH 3
#define MTYP_NOEMPTY_BIT 128