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 */
|
if (pkt_len > 1) /* MySQL 4.1 protocol */
|
||||||
{
|
{
|
||||||
mysql->warning_count= uint2korr(cp+1);
|
mysql->warning_count= uint2korr(cp+1);
|
||||||
|
mysql->server_status= uint2korr(cp+3);
|
||||||
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
|
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
|
||||||
}
|
}
|
||||||
DBUG_PRINT("exit",("Got %d rows",result->rows));
|
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 <= 8 && mysql->net.read_pos[0] == 254)
|
||||||
{
|
{
|
||||||
if (pkt_len > 1) /* MySQL 4.1 protocol */
|
if (pkt_len > 1) /* MySQL 4.1 protocol */
|
||||||
|
{
|
||||||
mysql->warning_count= uint2korr(mysql->net.read_pos+1);
|
mysql->warning_count= uint2korr(mysql->net.read_pos+1);
|
||||||
|
mysql->server_status= uint2korr(mysql->net.read_pos+3);
|
||||||
|
}
|
||||||
return 1; /* End of data */
|
return 1; /* End of data */
|
||||||
}
|
}
|
||||||
prev_pos= 0; /* allowed to write at packet[-1] */
|
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)
|
if (pkt_len > 1)
|
||||||
{
|
{
|
||||||
mysql->warning_count= uint2korr(cp+1);
|
mysql->warning_count= uint2korr(cp+1);
|
||||||
|
mysql->server_status= uint2korr(cp+3);
|
||||||
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
|
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
|
||||||
}
|
}
|
||||||
DBUG_PRINT("exit",("Got %d rows",result->rows));
|
DBUG_PRINT("exit",("Got %d rows",result->rows));
|
||||||
|
@ -58,9 +58,14 @@ declare y int;
|
|||||||
set x = y;
|
set x = y;
|
||||||
end;
|
end;
|
||||||
Referring to uninitialized variable y
|
Referring to uninitialized variable y
|
||||||
create procedure foo(x int)
|
create procedure foo()
|
||||||
select * from test.t1;
|
begin
|
||||||
|
select name from mysql.proc;
|
||||||
|
select type from mysql.proc;
|
||||||
|
end;
|
||||||
|
call foo();
|
||||||
SELECT in a stored procedure must have INTO
|
SELECT in a stored procedure must have INTO
|
||||||
|
drop procedure foo;
|
||||||
create procedure foo()
|
create procedure foo()
|
||||||
return 42;
|
return 42;
|
||||||
RETURN is only allowed in a FUNCTION
|
RETURN is only allowed in a FUNCTION
|
||||||
|
@ -89,10 +89,16 @@ begin
|
|||||||
set x = y;
|
set x = y;
|
||||||
end|
|
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
|
--error 1268
|
||||||
create procedure foo(x int)
|
call foo()|
|
||||||
select * from test.t1|
|
drop procedure foo|
|
||||||
|
|
||||||
# RETURN in FUNCTION only
|
# RETURN in FUNCTION only
|
||||||
--error 1269
|
--error 1269
|
||||||
|
@ -360,7 +360,7 @@ send_eof(THD *thd, bool no_flush)
|
|||||||
uint tmp= min(thd->total_warn_count, 65535);
|
uint tmp= min(thd->total_warn_count, 65535);
|
||||||
buff[0]=254;
|
buff[0]=254;
|
||||||
int2store(buff+1, tmp);
|
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(my_net_write(net,(char*) buff,5));
|
||||||
VOID(net_flush(net));
|
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)
|
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");
|
DBUG_ENTER("sp_head::sp_head");
|
||||||
const char *dstr = (const char*)lex->buf;
|
const char *dstr = (const char*)lex->buf;
|
||||||
|
@ -46,6 +46,8 @@ public:
|
|||||||
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
||||||
enum enum_field_types m_returns; // For FUNCTIONs only
|
enum enum_field_types m_returns; // For FUNCTIONs only
|
||||||
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
|
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
|
#if 0
|
||||||
// We're not using this at the moment.
|
// We're not using this at the moment.
|
||||||
List<char *> m_calls; // Called procedures.
|
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);
|
net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case SQLCOM_CALL:
|
case SQLCOM_CALL:
|
||||||
{
|
{
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
@ -3057,17 +3057,40 @@ mysql_execute_command(THD *thd)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
uint smrx;
|
||||||
|
LINT_INIT(smrx);
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
// When executing substatements, they're assumed to send_error when
|
// When executing substatements, they're assumed to send_error when
|
||||||
// it happens, but not to send_ok.
|
// it happens, but not to send_ok.
|
||||||
my_bool nsok= thd->net.no_send_ok;
|
my_bool nsok= thd->net.no_send_ok;
|
||||||
|
|
||||||
thd->net.no_send_ok= TRUE;
|
thd->net.no_send_ok= TRUE;
|
||||||
#endif
|
#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);
|
res= sp->execute_procedure(thd, &lex->value_list);
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
thd->net.no_send_ok= nsok;
|
thd->net.no_send_ok= nsok;
|
||||||
#endif
|
#endif
|
||||||
|
if (sp->m_multi_query)
|
||||||
|
{
|
||||||
|
if (! smrx)
|
||||||
|
thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||||
|
|
||||||
@ -3076,8 +3099,8 @@ mysql_execute_command(THD *thd)
|
|||||||
else
|
else
|
||||||
goto error; // Substatement should already have sent error
|
goto error; // Substatement should already have sent error
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case SQLCOM_ALTER_PROCEDURE:
|
case SQLCOM_ALTER_PROCEDURE:
|
||||||
case SQLCOM_ALTER_FUNCTION:
|
case SQLCOM_ALTER_FUNCTION:
|
||||||
{
|
{
|
||||||
@ -3099,8 +3122,8 @@ mysql_execute_command(THD *thd)
|
|||||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case SQLCOM_DROP_PROCEDURE:
|
case SQLCOM_DROP_PROCEDURE:
|
||||||
case SQLCOM_DROP_FUNCTION:
|
case SQLCOM_DROP_FUNCTION:
|
||||||
{
|
{
|
||||||
@ -3149,8 +3172,8 @@ mysql_execute_command(THD *thd)
|
|||||||
lex->udf.name.str);
|
lex->udf.name.str);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default: /* Impossible */
|
default: /* Impossible */
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
break;
|
break;
|
||||||
|
@ -940,6 +940,14 @@ create:
|
|||||||
lex->spcont= new sp_pcontext();
|
lex->spcont= new sp_pcontext();
|
||||||
lex->sphead= new sp_head(&$3, lex);
|
lex->sphead= new sp_head(&$3, lex);
|
||||||
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
|
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 ')'
|
'(' sp_pdparam_list ')'
|
||||||
{
|
{
|
||||||
@ -947,7 +955,12 @@ create:
|
|||||||
}
|
}
|
||||||
sp_proc_stmt
|
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->spcont= new sp_pcontext();
|
||||||
lex->sphead= new sp_head(&lex->udf.name, lex);
|
lex->sphead= new sp_head(&lex->udf.name, lex);
|
||||||
lex->sphead->m_type= TYPE_ENUM_FUNCTION;
|
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 ')'
|
sp_fdparam_list ')'
|
||||||
{
|
{
|
||||||
@ -987,7 +1008,12 @@ create_function_tail:
|
|||||||
}
|
}
|
||||||
sp_proc_stmt
|
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)
|
if (lex->sql_command == SQLCOM_SELECT && !lex->result)
|
||||||
{
|
{
|
||||||
send_error(YYTHD, ER_SP_BADSELECT);
|
/* We maybe have one or more SELECT without INTO */
|
||||||
YYABORT;
|
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.
|
/* Currently we can't handle queries inside a FUNCTION,
|
||||||
** (This happens if the SET only contained local variables,
|
** because of the way table locking works.
|
||||||
** which get their set instructions generated separately.)
|
** 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 ||
|
if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
|
||||||
!lex->var_list.is_empty())
|
lex->sql_command != SQLCOM_SET_OPTION)
|
||||||
{
|
{
|
||||||
/* Currently we can't handle queries inside a FUNCTION,
|
send_error(YYTHD, ER_SP_BADQUERY);
|
||||||
** because of the way table locking works.
|
YYABORT;
|
||||||
** This is unfortunate, and limits the usefulness of functions
|
}
|
||||||
** a great deal, but it's nothing we can do about this at the
|
else
|
||||||
** moment.
|
{
|
||||||
*/
|
sp_instr_stmt *i=new sp_instr_stmt(lex->sphead->instructions());
|
||||||
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);
|
i->set_lex(lex);
|
||||||
lex->sphead->add_instr(i);
|
lex->sphead->add_instr(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lex->sphead->restore_lex(YYTHD);
|
lex->sphead->restore_lex(YYTHD);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| RETURN_SYM expr
|
| RETURN_SYM expr
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user