mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Made multiple queries (SELECT without INTO) work in SPs.
This included bug fixes in the 4.1 protocol (actually send and receive the server_status flags). libmysql/libmysql.c: Pick up the server_status (with the 4.1 protocol) as well. mysql-test/r/sp-error.result: Test for "bad selects" in non-CLIENT_MULTI_QUERIES clients (as mysqltest for the momen; this test will have to go away eventually). mysql-test/t/sp-error.test: Test for "bad selects" in non-CLIENT_MULTI_QUERIES clients (as mysqltest for the momen; this test will have to go away eventually). sql/protocol.cc: Actually send the server_status flags in send_eof() (4.1 protocol), not just zero. sql/sp_head.cc: Made multiple queries (SELECT without INTO) work in SPs. sql/sp_head.h: Made multiple queries (SELECT without INTO) work in SPs. sql/sql_parse.cc: Made multiple queries (SELECT without INTO) work in SPs. sql/sql_yacc.yy: Made multiple queries (SELECT without INTO) work in SPs.
This commit is contained in:
@ -1370,6 +1370,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
|
||||
if (pkt_len > 1) /* MySQL 4.1 protocol */
|
||||
{
|
||||
mysql->warning_count= uint2korr(cp+1);
|
||||
mysql->server_status= uint2korr(cp+3);
|
||||
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
|
||||
}
|
||||
DBUG_PRINT("exit",("Got %d rows",result->rows));
|
||||
@ -1395,7 +1396,10 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
|
||||
if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
|
||||
{
|
||||
if (pkt_len > 1) /* MySQL 4.1 protocol */
|
||||
{
|
||||
mysql->warning_count= uint2korr(mysql->net.read_pos+1);
|
||||
mysql->server_status= uint2korr(mysql->net.read_pos+3);
|
||||
}
|
||||
return 1; /* End of data */
|
||||
}
|
||||
prev_pos= 0; /* allowed to write at packet[-1] */
|
||||
@ -5370,6 +5374,7 @@ static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt)
|
||||
if (pkt_len > 1)
|
||||
{
|
||||
mysql->warning_count= uint2korr(cp+1);
|
||||
mysql->server_status= uint2korr(cp+3);
|
||||
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
|
||||
}
|
||||
DBUG_PRINT("exit",("Got %d rows",result->rows));
|
||||
|
@ -58,9 +58,14 @@ declare y int;
|
||||
set x = y;
|
||||
end;
|
||||
Referring to uninitialized variable y
|
||||
create procedure foo(x int)
|
||||
select * from test.t1;
|
||||
create procedure foo()
|
||||
begin
|
||||
select name from mysql.proc;
|
||||
select type from mysql.proc;
|
||||
end;
|
||||
call foo();
|
||||
SELECT in a stored procedure must have INTO
|
||||
drop procedure foo;
|
||||
create procedure foo()
|
||||
return 42;
|
||||
RETURN is only allowed in a FUNCTION
|
||||
|
@ -89,10 +89,16 @@ begin
|
||||
set x = y;
|
||||
end|
|
||||
|
||||
# We require INTO in SELECTs (for now; this might change in the future)
|
||||
# We require INTO in SELECTs for some older clients (as mysql and mysqltest,
|
||||
# for now).
|
||||
create procedure foo()
|
||||
begin
|
||||
select name from mysql.proc;
|
||||
select type from mysql.proc;
|
||||
end|
|
||||
--error 1268
|
||||
create procedure foo(x int)
|
||||
select * from test.t1|
|
||||
call foo()|
|
||||
drop procedure foo|
|
||||
|
||||
# RETURN in FUNCTION only
|
||||
--error 1269
|
||||
|
@ -360,7 +360,7 @@ send_eof(THD *thd, bool no_flush)
|
||||
uint tmp= min(thd->total_warn_count, 65535);
|
||||
buff[0]=254;
|
||||
int2store(buff+1, tmp);
|
||||
int2store(buff+3, 0); // No flags yet
|
||||
int2store(buff+3, thd->server_status);
|
||||
VOID(my_net_write(net,(char*) buff,5));
|
||||
VOID(net_flush(net));
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ eval_func_item(THD *thd, Item *it, enum enum_field_types type)
|
||||
}
|
||||
|
||||
sp_head::sp_head(LEX_STRING *name, LEX *lex)
|
||||
: Sql_alloc(), m_simple_case(FALSE)
|
||||
: Sql_alloc(), m_simple_case(FALSE), m_multi_query(FALSE)
|
||||
{
|
||||
DBUG_ENTER("sp_head::sp_head");
|
||||
const char *dstr = (const char*)lex->buf;
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
||||
enum enum_field_types m_returns; // For FUNCTIONs only
|
||||
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
|
||||
my_bool m_multi_query; // TRUE if a procedure with SELECT(s)
|
||||
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
|
||||
#if 0
|
||||
// We're not using this at the moment.
|
||||
List<char *> m_calls; // Called procedures.
|
||||
|
@ -3043,8 +3043,8 @@ mysql_execute_command(THD *thd)
|
||||
net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_CALL:
|
||||
{
|
||||
sp_head *sp;
|
||||
@ -3057,17 +3057,40 @@ mysql_execute_command(THD *thd)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint smrx;
|
||||
LINT_INIT(smrx);
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
// When executing substatements, they're assumed to send_error when
|
||||
// it happens, but not to send_ok.
|
||||
my_bool nsok= thd->net.no_send_ok;
|
||||
|
||||
thd->net.no_send_ok= TRUE;
|
||||
#endif
|
||||
res= sp->execute_procedure(thd, &lex->value_list);
|
||||
if (sp->m_multi_query)
|
||||
{
|
||||
if (! (thd->client_capabilities & CLIENT_MULTI_QUERIES))
|
||||
{
|
||||
send_error(thd, ER_SP_BADSELECT);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
thd->net.no_send_ok= nsok;
|
||||
#endif
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
goto error;
|
||||
}
|
||||
smrx= thd->server_status & SERVER_MORE_RESULTS_EXISTS;
|
||||
thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
|
||||
}
|
||||
|
||||
res= sp->execute_procedure(thd, &lex->value_list);
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
thd->net.no_send_ok= nsok;
|
||||
#endif
|
||||
if (sp->m_multi_query)
|
||||
{
|
||||
if (! smrx)
|
||||
thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
|
||||
}
|
||||
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
|
||||
@ -3076,8 +3099,8 @@ mysql_execute_command(THD *thd)
|
||||
else
|
||||
goto error; // Substatement should already have sent error
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_ALTER_PROCEDURE:
|
||||
case SQLCOM_ALTER_FUNCTION:
|
||||
{
|
||||
@ -3099,8 +3122,8 @@ mysql_execute_command(THD *thd)
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
send_ok(thd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DROP_PROCEDURE:
|
||||
case SQLCOM_DROP_FUNCTION:
|
||||
{
|
||||
@ -3149,8 +3172,8 @@ mysql_execute_command(THD *thd)
|
||||
lex->udf.name.str);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: /* Impossible */
|
||||
send_ok(thd);
|
||||
break;
|
||||
|
@ -940,6 +940,14 @@ create:
|
||||
lex->spcont= new sp_pcontext();
|
||||
lex->sphead= new sp_head(&$3, lex);
|
||||
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
|
||||
/*
|
||||
* We have to turn of CLIENT_MULTI_QUERIES while parsing a
|
||||
* stored procedure, otherwise yylex will chop it into pieces
|
||||
* at each ';'.
|
||||
*/
|
||||
lex->sphead->m_old_cmq=
|
||||
YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||||
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
|
||||
}
|
||||
'(' sp_pdparam_list ')'
|
||||
{
|
||||
@ -947,7 +955,12 @@ create:
|
||||
}
|
||||
sp_proc_stmt
|
||||
{
|
||||
Lex->sql_command= SQLCOM_CREATE_PROCEDURE;
|
||||
LEX *lex= Lex;
|
||||
|
||||
lex->sql_command= SQLCOM_CREATE_PROCEDURE;
|
||||
/* Restore flag if it was cleared above */
|
||||
if (lex->sphead->m_old_cmq)
|
||||
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
||||
}
|
||||
;
|
||||
|
||||
@ -976,6 +989,14 @@ create_function_tail:
|
||||
lex->spcont= new sp_pcontext();
|
||||
lex->sphead= new sp_head(&lex->udf.name, lex);
|
||||
lex->sphead->m_type= TYPE_ENUM_FUNCTION;
|
||||
/*
|
||||
* We have to turn of CLIENT_MULTI_QUERIES while parsing a
|
||||
* stored procedure, otherwise yylex will chop it into pieces
|
||||
* at each ';'.
|
||||
*/
|
||||
lex->sphead->m_old_cmq=
|
||||
YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||||
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
|
||||
}
|
||||
sp_fdparam_list ')'
|
||||
{
|
||||
@ -987,7 +1008,12 @@ create_function_tail:
|
||||
}
|
||||
sp_proc_stmt
|
||||
{
|
||||
Lex->sql_command = SQLCOM_CREATE_SPFUNCTION;
|
||||
LEX *lex= Lex;
|
||||
|
||||
lex->sql_command = SQLCOM_CREATE_SPFUNCTION;
|
||||
/* Restore flag if it was cleared above */
|
||||
if (lex->sphead->m_old_cmq)
|
||||
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
||||
}
|
||||
;
|
||||
|
||||
@ -1140,11 +1166,9 @@ sp_proc_stmt:
|
||||
|
||||
if (lex->sql_command == SQLCOM_SELECT && !lex->result)
|
||||
{
|
||||
send_error(YYTHD, ER_SP_BADSELECT);
|
||||
YYABORT;
|
||||
/* We maybe have one or more SELECT without INTO */
|
||||
lex->sphead->m_multi_query= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't add an instruction for empty SET statements.
|
||||
** (This happens if the SET only contained local variables,
|
||||
** which get their set instructions generated separately.)
|
||||
@ -1174,7 +1198,6 @@ sp_proc_stmt:
|
||||
}
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
}
|
||||
}
|
||||
| RETURN_SYM expr
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
|
Reference in New Issue
Block a user