Commit a4e06592 authored by pem@mysql.com's avatar pem@mysql.com

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).
parent 7b5df9ed
......@@ -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 @@ class sp_head : public Sql_alloc
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;
}
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
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;
}
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;
}
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;
}
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,40 +1166,37 @@ 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.)
*/
if (lex->sql_command != SQLCOM_SET_OPTION ||
!lex->var_list.is_empty())
{
/* 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.)
/* Currently we can't handle queries inside a FUNCTION,
** because of the way table locking works.
** This is unfortunate, and limits the usefulness of functions
** a great deal, but it's nothing we can do about this at the
** moment.
*/
if (lex->sql_command != SQLCOM_SET_OPTION ||
!lex->var_list.is_empty())
if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
lex->sql_command != SQLCOM_SET_OPTION)
{
/* Currently we can't handle queries inside a FUNCTION,
** because of the way table locking works.
** This is unfortunate, and limits the usefulness of functions
** a great deal, but it's nothing we can do about this at the
** moment.
*/
if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
lex->sql_command != SQLCOM_SET_OPTION)
{
send_error(YYTHD, ER_SP_BADQUERY);
YYABORT;
}
else
{
sp_instr_stmt *i= new sp_instr_stmt(lex->sphead->instructions());
i->set_lex(lex);
lex->sphead->add_instr(i);
}
}
lex->sphead->restore_lex(YYTHD);
}
send_error(YYTHD, ER_SP_BADQUERY);
YYABORT;
}
else
{
sp_instr_stmt *i=new sp_instr_stmt(lex->sphead->instructions());
i->set_lex(lex);
lex->sphead->add_instr(i);
}
}
lex->sphead->restore_lex(YYTHD);
}
| RETURN_SYM expr
{
......
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