mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Background:
Since long, the compiled code of stored routines has been printed in the trace file when starting mysqld with the "--debug" flag. (At creation time only, and only in debug builds of course.) This has been helpful when debugging stored procedure execution, but it's a bit awkward to use. Also, the printing of some of the instructions is a bit terse, in particular for sp_instr_stmt where only the command code was printed. This improves the printout of several of the instructions, and adds the debugging- only commands "show procedure code <name>" and "show function code <name>". (In non-debug builds they are not available.)
This commit is contained in:
@ -110,6 +110,7 @@ static SYMBOL symbols[] = {
|
||||
{ "CIPHER", SYM(CIPHER_SYM)},
|
||||
{ "CLIENT", SYM(CLIENT_SYM)},
|
||||
{ "CLOSE", SYM(CLOSE_SYM)},
|
||||
{ "CODE", SYM(CODE_SYM)},
|
||||
{ "COLLATE", SYM(COLLATE_SYM)},
|
||||
{ "COLLATION", SYM(COLLATION_SYM)},
|
||||
{ "COLUMN", SYM(COLUMN_SYM)},
|
||||
|
167
sql/sp_head.cc
167
sql/sp_head.cc
@ -105,6 +105,8 @@ sp_get_flags_for_command(LEX *lex)
|
||||
case SQLCOM_SHOW_TABLES:
|
||||
case SQLCOM_SHOW_VARIABLES:
|
||||
case SQLCOM_SHOW_WARNS:
|
||||
case SQLCOM_SHOW_PROC_CODE:
|
||||
case SQLCOM_SHOW_FUNC_CODE:
|
||||
flags= sp_head::MULTI_RESULTS;
|
||||
break;
|
||||
/*
|
||||
@ -1698,7 +1700,7 @@ sp_head::show_create_procedure(THD *thd)
|
||||
LINT_INIT(sql_mode_len);
|
||||
|
||||
if (check_show_routine_access(thd, this, &full_access))
|
||||
return 1;
|
||||
DBUG_RETURN(1);
|
||||
|
||||
sql_mode_str=
|
||||
sys_var_thd_sql_mode::symbolic_mode_representation(thd,
|
||||
@ -1711,10 +1713,7 @@ sp_head::show_create_procedure(THD *thd)
|
||||
max(buffer.length(), 1024)));
|
||||
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
|
||||
Protocol::SEND_EOF))
|
||||
{
|
||||
res= 1;
|
||||
goto done;
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(m_name.str, m_name.length, system_charset_info);
|
||||
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
|
||||
@ -1723,7 +1722,6 @@ sp_head::show_create_procedure(THD *thd)
|
||||
res= protocol->write();
|
||||
send_eof(thd);
|
||||
|
||||
done:
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
@ -1768,7 +1766,7 @@ sp_head::show_create_function(THD *thd)
|
||||
LINT_INIT(sql_mode_len);
|
||||
|
||||
if (check_show_routine_access(thd, this, &full_access))
|
||||
return 1;
|
||||
DBUG_RETURN(1);
|
||||
|
||||
sql_mode_str=
|
||||
sys_var_thd_sql_mode::symbolic_mode_representation(thd,
|
||||
@ -1780,10 +1778,7 @@ sp_head::show_create_function(THD *thd)
|
||||
max(buffer.length(),1024)));
|
||||
if (protocol->send_fields(&field_list,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
||||
{
|
||||
res= 1;
|
||||
goto done;
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(m_name.str, m_name.length, system_charset_info);
|
||||
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
|
||||
@ -1792,7 +1787,6 @@ sp_head::show_create_function(THD *thd)
|
||||
res= protocol->write();
|
||||
send_eof(thd);
|
||||
|
||||
done:
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
@ -1852,6 +1846,51 @@ sp_head::opt_mark(uint ip)
|
||||
}
|
||||
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
int
|
||||
sp_head::show_routine_code(THD *thd)
|
||||
{
|
||||
Protocol *protocol= thd->protocol;
|
||||
char buff[2048];
|
||||
String buffer(buff, sizeof(buff), system_charset_info);
|
||||
int res;
|
||||
List<Item> field_list;
|
||||
bool full_access;
|
||||
uint ip;
|
||||
sp_instr *i;
|
||||
|
||||
DBUG_ENTER("sp_head::show_routine_code");
|
||||
DBUG_PRINT("info", ("procedure %s", m_name.str));
|
||||
|
||||
if (check_show_routine_access(thd, this, &full_access) || !full_access)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
field_list.push_back(new Item_uint("Pos", 9));
|
||||
// 1024 is for not to confuse old clients
|
||||
field_list.push_back(new Item_empty_string("Instruction",
|
||||
max(buffer.length(), 1024)));
|
||||
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
|
||||
Protocol::SEND_EOF))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
for (ip= 0; (i = get_instr(ip)) ; ip++)
|
||||
{
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store((longlong)ip);
|
||||
|
||||
buffer.set("", 0, system_charset_info);
|
||||
i->print(&buffer);
|
||||
protocol->store(buffer.c_ptr_quick(), buffer.length(), system_charset_info);
|
||||
if ((res= protocol->write()))
|
||||
break;
|
||||
}
|
||||
send_eof(thd);
|
||||
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
#endif // ifndef DBUG_OFF
|
||||
|
||||
|
||||
/*
|
||||
Prepare LEX and thread for execution of instruction, if requested open
|
||||
and lock LEX's tables, execute instruction's core function, perform
|
||||
@ -2010,14 +2049,34 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
#define STMT_PRINT_MAXLEN 40
|
||||
void
|
||||
sp_instr_stmt::print(String *str)
|
||||
{
|
||||
str->reserve(12);
|
||||
uint i, len;
|
||||
|
||||
str->reserve(STMT_PRINT_MAXLEN+20);
|
||||
str->append("stmt ");
|
||||
str->qs_append((uint)m_lex_keeper.sql_command());
|
||||
str->append(" \"");
|
||||
len= m_query.length;
|
||||
/*
|
||||
Print the query string (but not too much of it), just to indicate which
|
||||
statement it is.
|
||||
*/
|
||||
if (len > STMT_PRINT_MAXLEN)
|
||||
len= STMT_PRINT_MAXLEN-3;
|
||||
/* Copy the query string and replace '\n' with ' ' in the process */
|
||||
for (i= 0 ; i < len ; i++)
|
||||
if (m_query.str[i] == '\n')
|
||||
str->append(' ');
|
||||
else
|
||||
str->append(m_query.str[i]);
|
||||
if (m_query.length > STMT_PRINT_MAXLEN)
|
||||
str->append("..."); /* Indicate truncated string */
|
||||
str->append('"');
|
||||
}
|
||||
|
||||
#undef STMT_PRINT_MAXLEN
|
||||
|
||||
int
|
||||
sp_instr_stmt::exec_core(THD *thd, uint *nextp)
|
||||
@ -2054,8 +2113,19 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
|
||||
void
|
||||
sp_instr_set::print(String *str)
|
||||
{
|
||||
str->reserve(12);
|
||||
int rsrv = 16;
|
||||
sp_pvar_t *var = m_ctx->find_pvar(m_offset);
|
||||
|
||||
/* 'var' should always be non-null, but just in case... */
|
||||
if (var)
|
||||
rsrv+= var->name.length;
|
||||
str->reserve(rsrv);
|
||||
str->append("set ");
|
||||
if (var)
|
||||
{
|
||||
str->append(var->name.str, var->name.length);
|
||||
str->append('@');
|
||||
}
|
||||
str->qs_append(m_offset);
|
||||
str->append(' ');
|
||||
m_value->print(str);
|
||||
@ -2346,12 +2416,26 @@ sp_instr_hpush_jump::print(String *str)
|
||||
str->reserve(32);
|
||||
str->append("hpush_jump ");
|
||||
str->qs_append(m_dest);
|
||||
str->append(" t=");
|
||||
str->qs_append(m_type);
|
||||
str->append(" f=");
|
||||
str->append(' ');
|
||||
str->qs_append(m_frame);
|
||||
str->append(" h=");
|
||||
str->qs_append(m_ip+1);
|
||||
switch (m_type)
|
||||
{
|
||||
case SP_HANDLER_NONE:
|
||||
str->append(" NONE"); // This would be a bug
|
||||
break;
|
||||
case SP_HANDLER_EXIT:
|
||||
str->append(" EXIT");
|
||||
break;
|
||||
case SP_HANDLER_CONTINUE:
|
||||
str->append(" CONTINUE");
|
||||
break;
|
||||
case SP_HANDLER_UNDO:
|
||||
str->append(" UNDO");
|
||||
break;
|
||||
default:
|
||||
str->append(" UNKNOWN:"); // This would be a bug as well
|
||||
str->qs_append(m_type);
|
||||
}
|
||||
}
|
||||
|
||||
uint
|
||||
@ -2474,7 +2558,17 @@ sp_instr_cpush::execute(THD *thd, uint *nextp)
|
||||
void
|
||||
sp_instr_cpush::print(String *str)
|
||||
{
|
||||
LEX_STRING n;
|
||||
my_bool found= m_ctx->find_cursor(m_cursor, &n);
|
||||
|
||||
str->reserve(32);
|
||||
str->append("cpush ");
|
||||
if (found)
|
||||
{
|
||||
str->append(n.str, n.length);
|
||||
str->append('@');
|
||||
}
|
||||
str->qs_append(m_cursor);
|
||||
}
|
||||
|
||||
|
||||
@ -2570,8 +2664,16 @@ sp_instr_copen::exec_core(THD *thd, uint *nextp)
|
||||
void
|
||||
sp_instr_copen::print(String *str)
|
||||
{
|
||||
str->reserve(12);
|
||||
LEX_STRING n;
|
||||
my_bool found= m_ctx->find_cursor(m_cursor, &n);
|
||||
|
||||
str->reserve(32);
|
||||
str->append("copen ");
|
||||
if (found)
|
||||
{
|
||||
str->append(n.str, n.length);
|
||||
str->append('@');
|
||||
}
|
||||
str->qs_append(m_cursor);
|
||||
}
|
||||
|
||||
@ -2599,8 +2701,16 @@ sp_instr_cclose::execute(THD *thd, uint *nextp)
|
||||
void
|
||||
sp_instr_cclose::print(String *str)
|
||||
{
|
||||
str->reserve(12);
|
||||
LEX_STRING n;
|
||||
my_bool found= m_ctx->find_cursor(m_cursor, &n);
|
||||
|
||||
str->reserve(32);
|
||||
str->append("cclose ");
|
||||
if (found)
|
||||
{
|
||||
str->append(n.str, n.length);
|
||||
str->append('@');
|
||||
}
|
||||
str->qs_append(m_cursor);
|
||||
}
|
||||
|
||||
@ -2629,14 +2739,23 @@ sp_instr_cfetch::print(String *str)
|
||||
{
|
||||
List_iterator_fast<struct sp_pvar> li(m_varlist);
|
||||
sp_pvar_t *pv;
|
||||
LEX_STRING n;
|
||||
my_bool found= m_ctx->find_cursor(m_cursor, &n);
|
||||
|
||||
str->reserve(12);
|
||||
str->reserve(32);
|
||||
str->append("cfetch ");
|
||||
if (found)
|
||||
{
|
||||
str->append(n.str, n.length);
|
||||
str->append('@');
|
||||
}
|
||||
str->qs_append(m_cursor);
|
||||
while ((pv= li++))
|
||||
{
|
||||
str->reserve(8);
|
||||
str->reserve(16);
|
||||
str->append(' ');
|
||||
str->append(pv->name.str, pv->name.length);
|
||||
str->append('@');
|
||||
str->qs_append(pv->offset);
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +295,12 @@ public:
|
||||
return test(m_flags &
|
||||
(CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT));
|
||||
}
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
int show_routine_code(THD *thd);
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
|
||||
MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
|
||||
@ -856,8 +862,8 @@ class sp_instr_cpush : public sp_instr
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex)
|
||||
: sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
|
||||
sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex, uint offset)
|
||||
: sp_instr(ip, ctx), m_lex_keeper(lex, TRUE), m_cursor(offset)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_cpush()
|
||||
@ -876,6 +882,7 @@ public:
|
||||
private:
|
||||
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
uint m_cursor; /* Frame offset (for debugging) */
|
||||
|
||||
}; // class sp_instr_cpush : public sp_instr
|
||||
|
||||
|
@ -169,6 +169,29 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Find a variable by offset from the top.
|
||||
This used for two things:
|
||||
- When evaluating parameters at the beginning, and setting out parameters
|
||||
at the end, of invokation. (Top frame only, so no recursion then.)
|
||||
- For printing of sp_instr_set. (Debug mode only.)
|
||||
*/
|
||||
sp_pvar_t *
|
||||
sp_pcontext::find_pvar(uint i)
|
||||
{
|
||||
if (m_poffset <= i && i < m_poffset + m_pvar.elements)
|
||||
{ // This frame
|
||||
sp_pvar_t *p;
|
||||
|
||||
get_dynamic(&m_pvar, (gptr)&p, i - m_poffset);
|
||||
return p;
|
||||
}
|
||||
else if (m_parent)
|
||||
return m_parent->find_pvar(i); // Some previous frame
|
||||
else
|
||||
return NULL; // index out of bounds
|
||||
}
|
||||
|
||||
void
|
||||
sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
|
||||
sp_param_mode_t mode)
|
||||
@ -331,3 +354,22 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
|
||||
return m_parent->find_cursor(name, poff, scoped);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
Find a cursor by offset from the top.
|
||||
This is only used for debugging.
|
||||
*/
|
||||
my_bool
|
||||
sp_pcontext::find_cursor(uint i, LEX_STRING *n)
|
||||
{
|
||||
if (m_coffset <= i && i < m_coffset + m_cursor.elements)
|
||||
{ // This frame
|
||||
get_dynamic(&m_cursor, (gptr)n, i - m_poffset);
|
||||
return TRUE;
|
||||
}
|
||||
else if (m_parent)
|
||||
return m_parent->find_cursor(i, n); // Some previous frame
|
||||
else
|
||||
return FALSE; // index out of bounds
|
||||
}
|
||||
|
||||
|
@ -172,16 +172,7 @@ class sp_pcontext : public Sql_alloc
|
||||
|
||||
// Find by index
|
||||
sp_pvar_t *
|
||||
find_pvar(uint i)
|
||||
{
|
||||
sp_pvar_t *p;
|
||||
|
||||
if (i < m_pvar.elements)
|
||||
get_dynamic(&m_pvar, (gptr)&p, i);
|
||||
else
|
||||
p= NULL;
|
||||
return p;
|
||||
}
|
||||
find_pvar(uint i);
|
||||
|
||||
//
|
||||
// Labels
|
||||
@ -261,6 +252,10 @@ class sp_pcontext : public Sql_alloc
|
||||
my_bool
|
||||
find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
|
||||
|
||||
/* Find by index (for debugging only) */
|
||||
my_bool
|
||||
find_cursor(uint i, LEX_STRING *n);
|
||||
|
||||
inline uint
|
||||
max_cursors()
|
||||
{
|
||||
|
@ -90,6 +90,7 @@ enum enum_sql_command {
|
||||
SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
|
||||
SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
|
||||
SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
|
||||
SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
|
||||
/* This should be the last !!! */
|
||||
|
||||
SQLCOM_END
|
||||
|
@ -4560,6 +4560,30 @@ end_with_restore_list:
|
||||
lex->wild->ptr() : NullS));
|
||||
break;
|
||||
}
|
||||
#ifndef DBUG_OFF
|
||||
case SQLCOM_SHOW_PROC_CODE:
|
||||
case SQLCOM_SHOW_FUNC_CODE:
|
||||
{
|
||||
sp_head *sp;
|
||||
|
||||
if (lex->spname->m_name.length > NAME_LEN)
|
||||
{
|
||||
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
|
||||
goto error;
|
||||
}
|
||||
if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
|
||||
sp= sp_find_procedure(thd, lex->spname);
|
||||
else
|
||||
sp= sp_find_function(thd, lex->spname);
|
||||
if (!sp || !sp->show_routine_code(thd))
|
||||
{ /* We don't distinguish between errors for now */
|
||||
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
|
||||
SP_COM_STRING(lex), lex->spname->m_name.str);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif // ifndef DBUG_OFF
|
||||
case SQLCOM_CREATE_VIEW:
|
||||
{
|
||||
if (end_active_trans(thd))
|
||||
|
@ -175,6 +175,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token CLIENT_SYM
|
||||
%token CLOSE_SYM
|
||||
%token COALESCE
|
||||
%token CODE_SYM
|
||||
%token COLLATE_SYM
|
||||
%token COLLATION_SYM
|
||||
%token COLUMNS
|
||||
@ -1698,7 +1699,8 @@ sp_decl:
|
||||
delete $5;
|
||||
YYABORT;
|
||||
}
|
||||
i= new sp_instr_cpush(sp->instructions(), ctx, $5);
|
||||
i= new sp_instr_cpush(sp->instructions(), ctx, $5,
|
||||
ctx->current_cursors());
|
||||
sp->add_instr(i);
|
||||
ctx->push_cursor(&$2);
|
||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||
@ -6625,7 +6627,28 @@ show_param:
|
||||
YYABORT;
|
||||
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
|
||||
YYABORT;
|
||||
};
|
||||
}
|
||||
| PROCEDURE CODE_SYM sp_name
|
||||
{
|
||||
#ifdef DBUG_OFF
|
||||
yyerror(ER(ER_SYNTAX_ERROR));
|
||||
YYABORT;
|
||||
#else
|
||||
Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
|
||||
Lex->spname= $3;
|
||||
#endif
|
||||
}
|
||||
| FUNCTION_SYM CODE_SYM sp_name
|
||||
{
|
||||
#ifdef DBUG_OFF
|
||||
yyerror(ER(ER_SYNTAX_ERROR));
|
||||
YYABORT;
|
||||
#else
|
||||
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
|
||||
Lex->spname= $3;
|
||||
#endif
|
||||
}
|
||||
;
|
||||
|
||||
show_engine_param:
|
||||
STATUS_SYM
|
||||
@ -7534,6 +7557,7 @@ keyword_sp:
|
||||
| CHANGED {}
|
||||
| CIPHER_SYM {}
|
||||
| CLIENT_SYM {}
|
||||
| CODE_SYM {}
|
||||
| COLLATION_SYM {}
|
||||
| COLUMNS {}
|
||||
| COMMITTED_SYM {}
|
||||
|
Reference in New Issue
Block a user