From c518a2405fefd175030a0e9ff019dedb064f28e5 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Thu, 17 Nov 2005 11:11:48 +0100 Subject: [PATCH 1/4] 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 " and "show function code ". (In non-debug builds they are not available.) --- sql/lex.h | 1 + sql/sp_head.cc | 169 ++++++++++++++++++++++++++++++++++++++------- sql/sp_head.h | 11 ++- sql/sp_pcontext.cc | 42 +++++++++++ sql/sp_pcontext.h | 15 ++-- sql/sql_lex.h | 1 + sql/sql_parse.cc | 24 +++++++ sql/sql_yacc.yy | 28 +++++++- 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 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 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 {} From 3a832faafecefdd0b83b8ba0be8ea28528f04b8d Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Fri, 18 Nov 2005 16:30:27 +0100 Subject: [PATCH 2/4] Post-review fixes, mainly fixing all print() methods for sp_instr* classes. Also added mysql-test files: include/is_debug_build.inc r/is_debug_build.require r/sp-code.result t/sp-code.test --- mysql-test/include/is_debug_build.inc | 4 + mysql-test/r/is_debug_build.require | 2 + mysql-test/r/sp-code.result | 65 +++++++++++ mysql-test/t/sp-code.test | 50 ++++++++ sql/sp_head.cc | 162 +++++++++++++++----------- sql/sp_pcontext.cc | 26 ++--- sql/sp_pcontext.h | 8 +- sql/sql_parse.cc | 3 +- 8 files changed, 235 insertions(+), 85 deletions(-) create mode 100644 mysql-test/include/is_debug_build.inc create mode 100644 mysql-test/r/is_debug_build.require create mode 100644 mysql-test/r/sp-code.result create mode 100644 mysql-test/t/sp-code.test diff --git a/mysql-test/include/is_debug_build.inc b/mysql-test/include/is_debug_build.inc new file mode 100644 index 00000000000..23a2814e2bb --- /dev/null +++ b/mysql-test/include/is_debug_build.inc @@ -0,0 +1,4 @@ +-- require r/is_debug_build.require +--disable_query_log +select instr(version(), "debug") > 0; +--enable_query_log diff --git a/mysql-test/r/is_debug_build.require b/mysql-test/r/is_debug_build.require new file mode 100644 index 00000000000..4d77bcdc1ed --- /dev/null +++ b/mysql-test/r/is_debug_build.require @@ -0,0 +1,2 @@ +instr(version(), "debug") > 0 +1 diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result new file mode 100644 index 00000000000..e9597af10ee --- /dev/null +++ b/mysql-test/r/sp-code.result @@ -0,0 +1,65 @@ +select version(), substring_index(version(), "-", -1); +version() substring_index(version(), "-", -1) +5.0.17-debug-log log +create procedure empty() +begin +end; +show procedure code empty; +Pos Instruction +drop procedure empty; +create function almost_empty() +returns int +return 0; +show function code almost_empty; +Pos Instruction +0 freturn 3 0 +drop function almost_empty; +create procedure code_sample(x int, out err int, out nulls int) +begin +declare count int default 0; +set nulls = 0; +begin +declare c cursor for select name from t1; +declare exit handler for not found close c; +open c; +loop +begin +declare n varchar(20); +declare continue handler for sqlexception set err=1; +fetch c into n; +if isnull(n) then +set nulls = nulls + 1; +else +set count = count + 1; +update t2 set idx = count where name=n; +end if; +end; +end loop; +end; +select t.name, t.idx from t2 t order by idx asc; +end// +show procedure code code_sample; +Pos Instruction +0 set count@3 0 +1 set nulls@2 0 +2 cpush c@0 +3 hpush_jump 6 4 EXIT +4 cclose c@0 +5 hreturn 0 19 +6 copen c@0 +7 set n@4 NULL +8 hpush_jump 11 5 CONTINUE +9 set err@1 1 +10 hreturn 5 +11 cfetch c@0 n@4 +12 jump_if_not 15 isnull(n@4) +13 set nulls@2 (nulls@2 + 1) +14 jump 17 +15 set count@3 (count@3 + 1) +16 stmt 4 "update t2 set idx = count where name=n" +17 hpop 1 +18 jump 7 +19 hpop 1 +20 cpop 1 +21 stmt 0 "select t.name, t.idx from t2 t order ..." +drop procedure code_sample; diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test new file mode 100644 index 00000000000..a40d86f9d4a --- /dev/null +++ b/mysql-test/t/sp-code.test @@ -0,0 +1,50 @@ +# +# Test the debugging feature "show procedure/function code " +# + +-- source include/is_debug_build.inc +select version(), substring_index(version(), "-", -1); + +create procedure empty() +begin +end; +show procedure code empty; +drop procedure empty; + +create function almost_empty() + returns int + return 0; +show function code almost_empty; +drop function almost_empty; + +delimiter //; +create procedure code_sample(x int, out err int, out nulls int) +begin + declare count int default 0; + + set nulls = 0; + begin + declare c cursor for select name from t1; + declare exit handler for not found close c; + + open c; + loop + begin + declare n varchar(20); + declare continue handler for sqlexception set err=1; + + fetch c into n; + if isnull(n) then + set nulls = nulls + 1; + else + set count = count + 1; + update t2 set idx = count where name=n; + end if; + end; + end loop; + end; + select t.name, t.idx from t2 t order by idx asc; +end// +delimiter ;// +show procedure code code_sample; +drop procedure code_sample; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1ab562b53fc..b11260ab999 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1853,14 +1853,13 @@ 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 field_list; - bool full_access; - uint ip; sp_instr *i; - + bool full_access; + int res; + uint ip; DBUG_ENTER("sp_head::show_routine_code"); - DBUG_PRINT("info", ("procedure %s", m_name.str)); + DBUG_PRINT("info", ("procedure: %s", m_name.str)); if (check_show_routine_access(thd, this, &full_access) || !full_access) DBUG_RETURN(1); @@ -1880,7 +1879,7 @@ sp_head::show_routine_code(THD *thd) buffer.set("", 0, system_charset_info); i->print(&buffer); - protocol->store(buffer.c_ptr_quick(), buffer.length(), system_charset_info); + protocol->store(buffer.ptr(), buffer.length(), system_charset_info); if ((res= protocol->write())) break; } @@ -2055,10 +2054,12 @@ sp_instr_stmt::print(String *str) { uint i, len; - str->reserve(STMT_PRINT_MAXLEN+20); - str->append("stmt "); + /* Reserve enough space for 'stmt CMD "..."'; max+20 is more than enough. */ + if (str->reserve(STMT_PRINT_MAXLEN+20)) + return; + str->qs_append("stmt ", 5); str->qs_append((uint)m_lex_keeper.sql_command()); - str->append(" \""); + str->qs_append(" \"", 2); len= m_query.length; /* Print the query string (but not too much of it), just to indicate which @@ -2068,13 +2069,15 @@ sp_instr_stmt::print(String *str) 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(' '); + str->qs_append(' '); else - str->append(m_query.str[i]); + str->qs_append(m_query.str[i]); + } if (m_query.length > STMT_PRINT_MAXLEN) - str->append("..."); /* Indicate truncated string */ - str->append('"'); + str->qs_append("...", 3); /* Indicate truncated string */ + str->qs_append('"'); } #undef STMT_PRINT_MAXLEN @@ -2119,15 +2122,16 @@ sp_instr_set::print(String *str) /* 'var' should always be non-null, but just in case... */ if (var) rsrv+= var->name.length; - str->reserve(rsrv); - str->append("set "); + if (str->reserve(rsrv)) + return; + str->qs_append("set ", 4); if (var) { - str->append(var->name.str, var->name.length); - str->append('@'); + str->qs_append(var->name.str, var->name.length); + str->qs_append('@'); } str->qs_append(m_offset); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2184,8 +2188,9 @@ sp_instr_jump::execute(THD *thd, uint *nextp) void sp_instr_jump::print(String *str) { - str->reserve(12); - str->append("jump "); + if (str->reserve(12)) + return; + str->qs_append("jump ", 5); str->qs_append(m_dest); } @@ -2266,10 +2271,11 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if::print(String *str) { - str->reserve(12); - str->append("jump_if "); + if (str->reserve(32)) + return; + str->qs_append("jump_if ", 8); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2327,10 +2333,11 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - str->reserve(16); - str->append("jump_if_not "); + if (str->reserve(32)) + return; + str->qs_append("jump_if_not ", 12); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); m_expr->print(str); } @@ -2385,10 +2392,11 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) void sp_instr_freturn::print(String *str) { - str->reserve(12); - str->append("freturn "); + if (str->reserve(32)) + return; + str->qs_append("freturn ", 8); str->qs_append((uint)m_type); - str->append(' '); + str->qs_append(' '); m_value->print(str); } @@ -2413,27 +2421,28 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) void sp_instr_hpush_jump::print(String *str) { - str->reserve(32); - str->append("hpush_jump "); + if (str->reserve(32)) + return; + str->qs_append("hpush_jump ", 11); str->qs_append(m_dest); - str->append(' '); + str->qs_append(' '); str->qs_append(m_frame); switch (m_type) { case SP_HANDLER_NONE: - str->append(" NONE"); // This would be a bug + str->qs_append(" NONE", 5); // This would be a bug break; case SP_HANDLER_EXIT: - str->append(" EXIT"); + str->qs_append(" EXIT", 5); break; case SP_HANDLER_CONTINUE: - str->append(" CONTINUE"); + str->qs_append(" CONTINUE", 9); break; case SP_HANDLER_UNDO: - str->append(" UNDO"); + str->qs_append(" UNDO", 5); break; default: - str->append(" UNKNOWN:"); // This would be a bug as well + str->qs_append(" UNKNOWN:", 9); // This would be a bug as well str->qs_append(m_type); } } @@ -2470,8 +2479,9 @@ sp_instr_hpop::execute(THD *thd, uint *nextp) void sp_instr_hpop::print(String *str) { - str->reserve(12); - str->append("hpop "); + if (str->reserve(12)) + return; + str->qs_append("hpop ", 5); str->qs_append(m_count); } @@ -2505,12 +2515,13 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) void sp_instr_hreturn::print(String *str) { - str->reserve(16); - str->append("hreturn "); + if (str->reserve(20)) + return; + str->qs_append("hreturn ", 8); str->qs_append(m_frame); if (m_dest) { - str->append(' '); + str->qs_append(' '); str->qs_append(m_dest); } } @@ -2559,14 +2570,18 @@ void sp_instr_cpush::print(String *str) { LEX_STRING n; + uint rsrv= 12; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("cpush "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("cpush ", 6); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); } @@ -2589,8 +2604,9 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) void sp_instr_cpop::print(String *str) { - str->reserve(12); - str->append("cpop "); + if (str->reserve(12)) + return; + str->qs_append("cpop ", 5); str->qs_append(m_count); } @@ -2665,14 +2681,18 @@ void sp_instr_copen::print(String *str) { LEX_STRING n; + uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("copen "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("copen ", 6); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); } @@ -2702,14 +2722,18 @@ void sp_instr_cclose::print(String *str) { LEX_STRING n; + uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("cclose "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("cclose ", 7); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); } @@ -2740,22 +2764,27 @@ sp_instr_cfetch::print(String *str) List_iterator_fast li(m_varlist); sp_pvar_t *pv; LEX_STRING n; + uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); - str->reserve(32); - str->append("cfetch "); + if (found) + rsrv+= n.length; + if (str->reserve(rsrv)) + return; + str->qs_append("cfetch ", 7); if (found) { - str->append(n.str, n.length); - str->append('@'); + str->qs_append(n.str, n.length); + str->qs_append('@'); } str->qs_append(m_cursor); while ((pv= li++)) { - str->reserve(16); - str->append(' '); - str->append(pv->name.str, pv->name.length); - str->append('@'); + if (str->reserve(pv->name.length+10)) + return; + str->qs_append(' '); + str->qs_append(pv->name.str, pv->name.length); + str->qs_append('@'); str->qs_append(pv->offset); } } @@ -2779,8 +2808,9 @@ sp_instr_error::execute(THD *thd, uint *nextp) void sp_instr_error::print(String *str) { - str->reserve(12); - str->append("error "); + if (str->reserve(12)) + return; + str->qs_append("error ", 6); str->qs_append(m_errcode); } diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 32824b75847..147173ab4d8 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -177,19 +177,18 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) - For printing of sp_instr_set. (Debug mode only.) */ sp_pvar_t * -sp_pcontext::find_pvar(uint i) +sp_pcontext::find_pvar(uint offset) { - if (m_poffset <= i && i < m_poffset + m_pvar.elements) + if (m_poffset <= offset && offset < m_poffset + m_pvar.elements) { // This frame sp_pvar_t *p; - get_dynamic(&m_pvar, (gptr)&p, i - m_poffset); + get_dynamic(&m_pvar, (gptr)&p, offset - m_poffset); return p; } - else if (m_parent) - return m_parent->find_pvar(i); // Some previous frame - else - return NULL; // index out of bounds + if (m_parent) + return m_parent->find_pvar(offset); // Some previous frame + return NULL; // index out of bounds } void @@ -360,16 +359,15 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) This is only used for debugging. */ my_bool -sp_pcontext::find_cursor(uint i, LEX_STRING *n) +sp_pcontext::find_cursor(uint offset, LEX_STRING *n) { - if (m_coffset <= i && i < m_coffset + m_cursor.elements) + if (m_coffset <= offset && offset < m_coffset + m_cursor.elements) { // This frame - get_dynamic(&m_cursor, (gptr)n, i - m_poffset); + get_dynamic(&m_cursor, (gptr)n, offset - m_coffset); return TRUE; } - else if (m_parent) - return m_parent->find_cursor(i, n); // Some previous frame - else - return FALSE; // index out of bounds + if (m_parent) + return m_parent->find_cursor(offset, n); // Some previous frame + return FALSE; // index out of bounds } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 77e749fe3ad..b8dd1742f7e 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -170,9 +170,9 @@ class sp_pcontext : public Sql_alloc sp_pvar_t * find_pvar(LEX_STRING *name, my_bool scoped=0); - // Find by index + // Find by offset sp_pvar_t * - find_pvar(uint i); + find_pvar(uint offset); // // Labels @@ -252,9 +252,9 @@ 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) */ + /* Find by offset (for debugging only) */ my_bool - find_cursor(uint i, LEX_STRING *n); + find_cursor(uint offset, LEX_STRING *n); inline uint max_cursors() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f46f0d3e5a1..5eafda5f685 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4576,7 +4576,8 @@ end_with_restore_list: else sp= sp_find_function(thd, lex->spname); if (!sp || !sp->show_routine_code(thd)) - { /* We don't distinguish between errors for now */ + { + /* 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; From 4513ffd109f2687e0c8ed575e31d197b15a7beeb Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Fri, 18 Nov 2005 18:05:04 +0100 Subject: [PATCH 3/4] Removed forgotten test line in sp-code.test. --- mysql-test/r/sp-code.result | 3 --- mysql-test/t/sp-code.test | 1 - 2 files changed, 4 deletions(-) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index e9597af10ee..e6c4ffe1731 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -1,6 +1,3 @@ -select version(), substring_index(version(), "-", -1); -version() substring_index(version(), "-", -1) -5.0.17-debug-log log create procedure empty() begin end; diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index a40d86f9d4a..6644bc3ab43 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -3,7 +3,6 @@ # -- source include/is_debug_build.inc -select version(), substring_index(version(), "-", -1); create procedure empty() begin From 962d2df6b00a5360c44bad5bf59c547b49c82b45 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 22 Nov 2005 13:06:52 +0100 Subject: [PATCH 4/4] Some final cleanup of the sp_instr print methods. --- sql/sp_head.cc | 65 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b11260ab999..c208840155d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2048,14 +2048,19 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } -#define STMT_PRINT_MAXLEN 40 +/* + Sufficient max length of printed destinations and frame offsets (all uints). +*/ +#define SP_INSTR_UINT_MAXLEN 8 + +#define SP_STMT_PRINT_MAXLEN 40 void sp_instr_stmt::print(String *str) { uint i, len; - /* Reserve enough space for 'stmt CMD "..."'; max+20 is more than enough. */ - if (str->reserve(STMT_PRINT_MAXLEN+20)) + /* stmt CMD "..." */ + if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8)) return; str->qs_append("stmt ", 5); str->qs_append((uint)m_lex_keeper.sql_command()); @@ -2065,8 +2070,8 @@ sp_instr_stmt::print(String *str) 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; + if (len > SP_STMT_PRINT_MAXLEN) + len= SP_STMT_PRINT_MAXLEN-3; /* Copy the query string and replace '\n' with ' ' in the process */ for (i= 0 ; i < len ; i++) { @@ -2075,11 +2080,11 @@ sp_instr_stmt::print(String *str) else str->qs_append(m_query.str[i]); } - if (m_query.length > STMT_PRINT_MAXLEN) + if (m_query.length > SP_STMT_PRINT_MAXLEN) str->qs_append("...", 3); /* Indicate truncated string */ str->qs_append('"'); } -#undef STMT_PRINT_MAXLEN +#undef SP_STMT_PRINT_MAXLEN int sp_instr_stmt::exec_core(THD *thd, uint *nextp) @@ -2116,7 +2121,8 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) void sp_instr_set::print(String *str) { - int rsrv = 16; + /* set name@offset ... */ + int rsrv = SP_INSTR_UINT_MAXLEN+6; sp_pvar_t *var = m_ctx->find_pvar(m_offset); /* 'var' should always be non-null, but just in case... */ @@ -2164,7 +2170,7 @@ sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) void sp_instr_set_trigger_field::print(String *str) { - str->append("set ", 4); + str->append("set_trigger_field ", 18); trigger_field->print(str); str->append(":=", 2); value->print(str); @@ -2188,7 +2194,8 @@ sp_instr_jump::execute(THD *thd, uint *nextp) void sp_instr_jump::print(String *str) { - if (str->reserve(12)) + /* jump dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) return; str->qs_append("jump ", 5); str->qs_append(m_dest); @@ -2271,7 +2278,8 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if::print(String *str) { - if (str->reserve(32)) + /* jump_if dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too return; str->qs_append("jump_if ", 8); str->qs_append(m_dest); @@ -2333,7 +2341,8 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - if (str->reserve(32)) + /* jump_if_not dest ... */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too return; str->qs_append("jump_if_not ", 12); str->qs_append(m_dest); @@ -2392,7 +2401,8 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) void sp_instr_freturn::print(String *str) { - if (str->reserve(32)) + /* freturn type expr... */ + if (str->reserve(UINT_MAX+8+32)) // Add some for the expr. too return; str->qs_append("freturn ", 8); str->qs_append((uint)m_type); @@ -2421,7 +2431,8 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) void sp_instr_hpush_jump::print(String *str) { - if (str->reserve(32)) + /* hpush_jump dest fsize type */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21)) return; str->qs_append("hpush_jump ", 11); str->qs_append(m_dest); @@ -2479,7 +2490,8 @@ sp_instr_hpop::execute(THD *thd, uint *nextp) void sp_instr_hpop::print(String *str) { - if (str->reserve(12)) + /* hpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) return; str->qs_append("hpop ", 5); str->qs_append(m_count); @@ -2515,7 +2527,8 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) void sp_instr_hreturn::print(String *str) { - if (str->reserve(20)) + /* hreturn framesize dest */ + if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9)) return; str->qs_append("hreturn ", 8); str->qs_append(m_frame); @@ -2570,8 +2583,9 @@ void sp_instr_cpush::print(String *str) { LEX_STRING n; - uint rsrv= 12; my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cpush name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+7; if (found) rsrv+= n.length; @@ -2604,7 +2618,8 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) void sp_instr_cpop::print(String *str) { - if (str->reserve(12)) + /* cpop count */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) return; str->qs_append("cpop ", 5); str->qs_append(m_count); @@ -2681,8 +2696,9 @@ void sp_instr_copen::print(String *str) { LEX_STRING n; - uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* copen name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+7; if (found) rsrv+= n.length; @@ -2722,8 +2738,9 @@ void sp_instr_cclose::print(String *str) { LEX_STRING n; - uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cclose name@offset */ + uint rsrv= SP_INSTR_UINT_MAXLEN+8; if (found) rsrv+= n.length; @@ -2764,8 +2781,9 @@ sp_instr_cfetch::print(String *str) List_iterator_fast li(m_varlist); sp_pvar_t *pv; LEX_STRING n; - uint rsrv= 16; my_bool found= m_ctx->find_cursor(m_cursor, &n); + /* cfetch name@offset vars... */ + uint rsrv= SP_INSTR_UINT_MAXLEN+8; if (found) rsrv+= n.length; @@ -2780,7 +2798,7 @@ sp_instr_cfetch::print(String *str) str->qs_append(m_cursor); while ((pv= li++)) { - if (str->reserve(pv->name.length+10)) + if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) return; str->qs_append(' '); str->qs_append(pv->name.str, pv->name.length); @@ -2808,7 +2826,8 @@ sp_instr_error::execute(THD *thd, uint *nextp) void sp_instr_error::print(String *str) { - if (str->reserve(12)) + /* error code */ + if (str->reserve(SP_INSTR_UINT_MAXLEN+6)) return; str->qs_append("error ", 6); str->qs_append(m_errcode);