summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2005-11-17 11:11:48 +0100
committerunknown <pem@mysql.com>2005-11-17 11:11:48 +0100
commit91ab707678870966b9410cd3bdd783eb2a7c19e4 (patch)
tree56f597a525587468da328317b4cb9b936d5a2d3f
parent14637f97cdd7ff4a7d60c09052e2e280ee57c957 (diff)
downloadmariadb-git-91ab707678870966b9410cd3bdd783eb2a7c19e4.tar.gz
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.) sql/lex.h: New symbol for debug-only command (e.g. show procedure code). sql/sp_head.cc: Fixed some minor debug-mode bugs in show_create_*(). New method for debugging: sp_head::show_routine_code() - returns the "assembly code" for a stored routine as a result set. Improved the print() methods for many sp_instr* classes, particularly for sp_instr_stmt where the query string is printed as well (up to a max length, just to give a hint of which statement it is). Also print the names of variables and cursors in some instruction. sql/sp_head.h: New debugging-only method in sp_head: show_routine_code(). Added offset member to sp_instr_cpush for improved debug printing. sql/sp_pcontext.cc: Moved find_pvar(uint i) method from sp_pcontext.h, and made it work for all frames, not just the first one. (For debugging purposes) Added a similar find_cursor(uint i, ...) method, for debugging. sql/sp_pcontext.h: Moved find_pvar(uint i) method to sp_pcontext.cc. Added a similar find_cursor(uint i, ...) method, for debugging. sql/sql_lex.h: Added new sql_command codes for debugging. sql/sql_parse.cc: Added new commands for debugging, e.g. "show procedure code". sql/sql_yacc.yy: Added new commands for debugging purposes: "show procedure code ..." and "show function code ...". These are only enabled in debug builds, otherwise they result in a syntax error. (I.e. they don't exist)
-rw-r--r--sql/lex.h1
-rw-r--r--sql/sp_head.cc169
-rw-r--r--sql/sp_head.h11
-rw-r--r--sql/sp_pcontext.cc42
-rw-r--r--sql/sp_pcontext.h15
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc24
-rw-r--r--sql/sql_yacc.yy28
8 files changed, 252 insertions, 39 deletions
diff --git a/sql/lex.h b/sql/lex.h
index a5366742fd9..efcb9b84f81 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -110,6 +110,7 @@ static SYMBOL symbols[] = {
{ "CIPHER", SYM(CIPHER_SYM)},
{ "CLIENT", SYM(CLIENT_SYM)},
{ "CLOSE", SYM(CLOSE_SYM)},
+ { "CODE", SYM(CODE_SYM)},
{ "COLLATE", SYM(COLLATE_SYM)},
{ "COLLATION", SYM(COLLATION_SYM)},
{ "COLUMN", SYM(COLUMN_SYM)},
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 08a189165b5..1ab562b53fc 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -105,6 +105,8 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_WARNS:
+ case SQLCOM_SHOW_PROC_CODE:
+ case SQLCOM_SHOW_FUNC_CODE:
flags= sp_head::MULTI_RESULTS;
break;
/*
@@ -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)
{
- str->append("cpush");
+ 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);
}
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index d1a122fd410..8055a04151f 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -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
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index f873b676925..32824b75847 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -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
+}
+
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index bd2259cb6fb..77e749fe3ad 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -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()
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 0e836b6e9b9..372bbc5576b 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -90,6 +90,7 @@ enum enum_sql_command {
SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
+ SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
/* This should be the last !!! */
SQLCOM_END
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c19d54feda5..f46f0d3e5a1 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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))
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 55002def5e9..2901698dd70 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -175,6 +175,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CLIENT_SYM
%token CLOSE_SYM
%token COALESCE
+%token CODE_SYM
%token COLLATE_SYM
%token COLLATION_SYM
%token COLUMNS
@@ -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 {}