Commit 4937474f authored by Alexander Barkov's avatar Alexander Barkov

MDEV-13414 Fix the SP code to avoid excessive use of strlen

parent 71689875
......@@ -10773,3 +10773,22 @@ void Field::register_field_in_read_map()
}
bitmap_set_bit(table->read_set, field_index);
}
bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
{
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc= false;
THD *thd= get_thd();
sql_mode_t sql_mode_backup= thd->variables.sql_mode;
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
val_str(&str);
if (!(to->length= str.length()))
*to= empty_clex_str;
else if ((rc= !(to->str= strmake_root(mem_root, str.ptr(), str.length()))))
to->length= 0;
thd->variables.sql_mode= sql_mode_backup;
return rc;
}
......@@ -839,6 +839,21 @@ class Field: public Value_source
*/
virtual String *val_str(String*,String *)=0;
String *val_int_as_str(String *val_buffer, bool unsigned_flag);
/*
Return the field value as a LEX_CSTRING, without padding to full length
(MODE_PAD_CHAR_TO_FULL_LENGTH is temporarily suppressed during the call).
In case of an empty value, to[0] is assigned to empty_clex_string,
memory is not allocated.
In case of a non-empty value, the memory is allocated on mem_root.
In case of a memory allocation failure, to[0] is assigned to {NULL,0}.
@param [IN] mem_root store non-empty values here
@param [OUT to return the string here
@retval false (success)
@retval true (EOM)
*/
bool val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to);
fast_field_copier get_fast_field_copier(const Field *from);
/*
str_needs_quotes() returns TRUE if the value returned by val_str() needs
......
This diff is collapsed.
......@@ -213,10 +213,13 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup);
sp_head *
sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
String *name, sql_mode_t sql_mode,
sp_load_for_information_schema(THD *thd, TABLE *proc_table,
stored_procedure_type type,
const char *returns, const char *params,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
sql_mode_t sql_mode,
bool *free_sp_head);
bool load_charset(MEM_ROOT *mem_root,
......@@ -235,13 +238,12 @@ void sp_returns_type(THD *thd,
bool show_create_sp(THD *thd, String *buf,
stored_procedure_type type,
const char *db, ulong dblen,
const char *name, ulong namelen,
const char *params, ulong paramslen,
const char *returns, ulong returnslen,
const char *body, ulong bodylen,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const LEX_CSTRING *definer_user,
const LEX_CSTRING *definer_host,
const AUTHID &definer,
sql_mode_t sql_mode);
#endif /* _SP_H_ */
......@@ -2458,27 +2458,6 @@ sp_head::set_info(longlong created, longlong modified,
}
void
sp_head::set_definer(const char *definer, uint definerlen)
{
char user_name_holder[USERNAME_LENGTH + 1];
LEX_CSTRING user_name= { user_name_holder, USERNAME_LENGTH };
char host_name_holder[HOSTNAME_LENGTH + 1];
LEX_CSTRING host_name= { host_name_holder, HOSTNAME_LENGTH };
if (parse_user(definer, definerlen, user_name_holder, &user_name.length,
host_name_holder, &host_name.length) &&
user_name.length && !host_name.length)
{
// 'user@' -> 'user@%'
host_name= host_not_specified;
}
set_definer(&user_name, &host_name);
}
void
sp_head::reset_thd_mem_root(THD *thd)
{
......
......@@ -689,7 +689,12 @@ class sp_head :private Query_arena,
void set_info(longlong created, longlong modified,
const st_sp_chistics &chistics, sql_mode_t sql_mode);
void set_definer(const char *definer, uint definerlen);
void set_definer(const char *definer, uint definerlen)
{
AUTHID tmp;
tmp.parse(definer, definerlen);
m_definer.copy(mem_root, &tmp.user, &tmp.host);
}
void set_definer(const LEX_CSTRING *user_name, const LEX_CSTRING *host_name)
{
m_definer.copy(mem_root, user_name, host_name);
......
......@@ -7475,4 +7475,34 @@ void AUTHID::copy(MEM_ROOT *mem_root, const LEX_CSTRING *user_name,
}
/*
Set from a string in 'user@host' format.
This method resebmles parse_user(),
but does not need temporary buffers.
*/
void AUTHID::parse(const char *str, size_t length)
{
const char *p= strrchr(str, '@');
if (!p)
{
user.str= str;
user.length= length;
host= null_clex_str;
}
else
{
user.str= str;
user.length= (size_t) (p - str);
host.str= p + 1;
host.length= (size_t) (length - user.length - 1);
if (user.length && !host.length)
host= host_not_specified; // 'user@' -> 'user@%'
}
if (user.length > USERNAME_LENGTH)
user.length= USERNAME_LENGTH;
if (host.length > HOSTNAME_LENGTH)
host.length= HOSTNAME_LENGTH;
}
#endif /* !defined(MYSQL_CLIENT) */
......@@ -1287,6 +1287,7 @@ struct st_sp_chistics
enum enum_sp_data_access daccess;
void init() { bzero(this, sizeof(*this)); }
void set(const st_sp_chistics &other) { *this= other; }
bool read_from_mysql_proc_row(THD *thd, TABLE *table);
};
......
......@@ -5876,14 +5876,9 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
TABLE_SHARE share;
TABLE tbl;
CHARSET_INFO *cs= system_charset_info;
char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
definer_buff[DEFINER_LENGTH + 1];
String params(params_buff, sizeof(params_buff), cs);
String returns(returns_buff, sizeof(returns_buff), cs);
String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
String definer(definer_buff, sizeof(definer_buff), cs);
LEX_CSTRING definer, params, returns= empty_clex_str;
LEX_CSTRING db, name;
char path[FN_REFLEN];
sp_head *sp;
stored_procedure_type routine_type;
bool free_sp_head;
......@@ -5894,48 +5889,44 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
(void) build_table_filename(path, sizeof(path), "", "", "", 0);
init_tmp_table_share(thd, &share, "", 0, "", path);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
routine_type= (stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
if (!full_access)
full_access= !strcmp(sp_user, definer.ptr());
full_access= !strcmp(sp_user, definer.str);
if (!full_access &&
check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
check_some_routine_access(thd, db.str, name.str,
routine_type == TYPE_ENUM_PROCEDURE))
DBUG_RETURN(0);
params.length(0);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params);
returns.length(0);
if (routine_type == TYPE_ENUM_FUNCTION)
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns);
sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
sp= sp_load_for_information_schema(thd, proc_table, routine_type, db, name,
params, returns,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
routine_type,
returns.c_ptr_safe(),
params.c_ptr_safe(),
&free_sp_head);
if (sp)
{
Field *field;
String tmp_string;
LEX_CSTRING tmp_string;
if (routine_type == TYPE_ENUM_FUNCTION)
{
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
table->field[1]->store(db, cs);
table->field[2]->store(name, cs);
table->field[3]->store((longlong) 0, TRUE);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
&tmp_string);
table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
table->field[15]->store(tmp_string, cs);
field= sp->m_return_field_def.make_field(&share, thd->mem_root,
&empty_clex_str);
field->table= &tbl;
......@@ -5973,16 +5964,16 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
table->field[1]->store(db, cs);
table->field[2]->store(name, cs);
table->field[3]->store((longlong) i + 1, TRUE);
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
table->field[4]->set_notnull();
table->field[5]->store(spvar->name.str, spvar->name.length, cs);
table->field[5]->set_notnull();
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
&tmp_string);
table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
table->field[15]->store(tmp_string, cs);
field= spvar->field_def.make_field(&share, thd->mem_root,
&spvar->name);
......@@ -6009,23 +6000,16 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
MYSQL_TIME time;
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
char sp_db_buff[SAFE_NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
definer_buff[DEFINER_LENGTH + 1],
returns_buff[MAX_FIELD_WIDTH];
String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
String definer(definer_buff, sizeof(definer_buff), cs);
String returns(returns_buff, sizeof(returns_buff), cs);
LEX_CSTRING db, name, definer, returns= empty_clex_str;
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
if (!full_access)
full_access= !strcmp(sp_user, definer.c_ptr_safe());
full_access= !strcmp(sp_user, definer.str);
if (!full_access &&
check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
check_some_routine_access(thd, db.str, name.str,
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
val_int() == TYPE_ENUM_PROCEDURE))
return 0;
......@@ -6040,15 +6024,15 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
{
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
sp_name.c_ptr_safe(), wild))
name.str, wild))
{
int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
table->field[3]->store(name, cs);
copy_field_as_string(table->field[0],
proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
table->field[1]->store(STRING_WITH_LEN("def"), cs);
table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
table->field[2]->store(db, cs);
copy_field_as_string(table->field[4],
proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
......@@ -6057,14 +6041,16 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
{
sp_head *sp;
bool free_sp_head;
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns);
sp= sp_load_for_information_schema(thd, proc_table,
TYPE_ENUM_FUNCTION, db, name,
empty_clex_str /*params*/,
returns,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->
val_int(),
TYPE_ENUM_FUNCTION,
returns.c_ptr_safe(),
"", &free_sp_head);
&free_sp_head);
if (sp)
{
......@@ -6115,7 +6101,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
copy_field_as_string(table->field[26],
proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
table->field[27]->store(definer.ptr(), definer.length(), cs);
table->field[27]->store(definer, cs);
copy_field_as_string(table->field[28],
proc_table->
field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
......
......@@ -471,6 +471,7 @@ class String
bool append(const char *s);
bool append(const LEX_STRING *ls) { return append(ls->str, ls->length); }
bool append(const LEX_CSTRING *ls) { return append(ls->str, ls->length); }
bool append(const LEX_CSTRING &ls) { return append(ls.str, ls.length); }
bool append(const char *s, uint32 arg_length);
bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool append_ulonglong(ulonglong val);
......
......@@ -221,6 +221,8 @@ struct AUTHID
l->length= strxmov(buf, user.str, "@", host.str, NullS) - buf;
}
}
void parse(const char *str, size_t length);
bool read_from_mysql_proc_row(THD *thd, TABLE *table);
};
......
......@@ -2236,6 +2236,7 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
sp_head *sp = thd->lex->sphead;
sql_mode_t saved_mode= thd->variables.sql_mode;
String retstr(64);
LEX_CSTRING returns= empty_clex_str;
retstr.set_charset(system_charset_info);
log_query.set_charset(system_charset_info);
......@@ -2243,18 +2244,14 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
if (sp->m_type == TYPE_ENUM_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring();
}
if (!show_create_sp(thd, &log_query,
sp->m_type,
(sp->m_explicit_name ? sp->m_db.str : NULL),
(sp->m_explicit_name ? sp->m_db.length : 0),
sp->m_name.str, sp->m_name.length,
sp->m_params.str, sp->m_params.length,
retstr.c_ptr(), retstr.length(),
sp->m_body.str, sp->m_body.length,
sp->chistics(), &(thd->lex->definer->user),
&(thd->lex->definer->host),
sp->m_explicit_name ? sp->m_db : null_clex_str,
sp->m_name, sp->m_params, returns,
sp->m_body, sp->chistics(), thd->lex->definer[0],
saved_mode))
{
WSREP_WARN("SP create string failed: schema: %s, query: %s",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment