mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-10580 sql_mode=ORACLE: FOR loop statement
Adding non-labeled FOR LOOP statement.
This commit is contained in:
@ -1504,7 +1504,7 @@ ERROR 42000: FUNCTION inexistent does not exist
|
||||
SELECT .inexistent();
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '()' at line 1
|
||||
SELECT ..inexistent();
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.inexistent()' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '..inexistent()' at line 1
|
||||
USE test;
|
||||
create function f1() returns int
|
||||
begin
|
||||
|
@ -560,3 +560,70 @@ Pos Instruction
|
||||
8 preturn
|
||||
9 hpop 1
|
||||
DROP PROCEDURE p1;
|
||||
# Testing FOR loop statement
|
||||
CREATE FUNCTION f1 (a INT, b INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN 1 .. a
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = b THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END
|
||||
/
|
||||
SHOW FUNCTION CODE f1;
|
||||
Pos Instruction
|
||||
0 set total@2 0
|
||||
1 set i@3 1
|
||||
2 set [upper_bound]@4 a@0
|
||||
3 jump_if_not 9(9) i@3 <= [upper_bound]@4
|
||||
4 set total@2 total@2 + i@3
|
||||
5 jump_if_not 7(7) i@3 = b@1
|
||||
6 jump 9
|
||||
7 set i@3 i@3 + 1
|
||||
8 jump 3
|
||||
9 freturn 3 total@2
|
||||
SELECT f1(3, 100) FROM DUAL;
|
||||
f1(3, 100)
|
||||
6
|
||||
SELECT f1(3, 2) FROM DUAL;
|
||||
f1(3, 2)
|
||||
3
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f1 (a INT, b INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN REVERSE a..1
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = b THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END
|
||||
/
|
||||
SHOW FUNCTION CODE f1;
|
||||
Pos Instruction
|
||||
0 set total@2 0
|
||||
1 set i@3 a@0
|
||||
2 set [upper_bound]@4 1
|
||||
3 jump_if_not 9(9) i@3 >= [upper_bound]@4
|
||||
4 set total@2 total@2 + i@3
|
||||
5 jump_if_not 7(7) i@3 = b@1
|
||||
6 jump 9
|
||||
7 set i@3 i@3 + -1
|
||||
8 jump 3
|
||||
9 freturn 3 total@2
|
||||
SELECT f1(3, 100) FROM DUAL;
|
||||
f1(3, 100)
|
||||
6
|
||||
SELECT f1(3, 2) FROM DUAL;
|
||||
f1(3, 2)
|
||||
5
|
||||
DROP FUNCTION f1;
|
||||
|
@ -774,3 +774,89 @@ SELECT @v;
|
||||
@v
|
||||
6
|
||||
DROP PROCEDURE p1;
|
||||
# Testing the FOR loop statement
|
||||
CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN lower_bound . . upper_bound
|
||||
LOOP
|
||||
NULL
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END;
|
||||
/
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '. upper_bound
|
||||
LOOP
|
||||
NULL
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END' at line 2
|
||||
CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN lower_bound .. upper_bound
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = lim THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
-- Bounds are calculated only once.
|
||||
-- The below assignments have no effect on the loop condition
|
||||
lower_bound:= 900;
|
||||
upper_bound:= 1000;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END;
|
||||
/
|
||||
SELECT f1(1, 3, 100) FROM DUAL;
|
||||
f1(1, 3, 100)
|
||||
6
|
||||
SELECT f1(1, 3, 2) FROM DUAL;
|
||||
f1(1, 3, 2)
|
||||
3
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN 1 .. 5
|
||||
LOOP
|
||||
total:= total + 1000;
|
||||
FOR j IN 1 .. 5
|
||||
LOOP
|
||||
total:= total + 1;
|
||||
IF j = 3 THEN
|
||||
EXIT; -- End the internal loop
|
||||
END IF;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END;
|
||||
/
|
||||
SELECT f1() FROM DUAL;
|
||||
f1()
|
||||
5015
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f1 (a INT, b INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN REVERSE a..1
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = b THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END
|
||||
/
|
||||
SELECT f1(3, 100) FROM DUAL;
|
||||
f1(3, 100)
|
||||
6
|
||||
SELECT f1(3, 2) FROM DUAL;
|
||||
f1(3, 2)
|
||||
5
|
||||
DROP FUNCTION f1;
|
||||
|
@ -441,3 +441,47 @@ END;
|
||||
DELIMITER ;/
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo # Testing FOR loop statement
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 (a INT, b INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN 1 .. a
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = b THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END
|
||||
/
|
||||
DELIMITER ;/
|
||||
SHOW FUNCTION CODE f1;
|
||||
SELECT f1(3, 100) FROM DUAL;
|
||||
SELECT f1(3, 2) FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 (a INT, b INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN REVERSE a..1
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = b THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END
|
||||
/
|
||||
DELIMITER ;/
|
||||
SHOW FUNCTION CODE f1;
|
||||
SELECT f1(3, 100) FROM DUAL;
|
||||
SELECT f1(3, 2) FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
@ -843,3 +843,91 @@ SET @v=0;
|
||||
CALL p1(@v);
|
||||
SELECT @v;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo # Testing the FOR loop statement
|
||||
|
||||
DELIMITER /;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN lower_bound . . upper_bound
|
||||
LOOP
|
||||
NULL
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN lower_bound .. upper_bound
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = lim THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
-- Bounds are calculated only once.
|
||||
-- The below assignments have no effect on the loop condition
|
||||
lower_bound:= 900;
|
||||
upper_bound:= 1000;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SELECT f1(1, 3, 100) FROM DUAL;
|
||||
SELECT f1(1, 3, 2) FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN 1 .. 5
|
||||
LOOP
|
||||
total:= total + 1000;
|
||||
FOR j IN 1 .. 5
|
||||
LOOP
|
||||
total:= total + 1;
|
||||
IF j = 3 THEN
|
||||
EXIT; -- End the internal loop
|
||||
END IF;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SELECT f1() FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 (a INT, b INT) RETURN INT
|
||||
AS
|
||||
total INT := 0;
|
||||
BEGIN
|
||||
FOR i IN REVERSE a..1
|
||||
LOOP
|
||||
total:= total + i;
|
||||
IF i = b THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN total;
|
||||
END
|
||||
/
|
||||
DELIMITER ;/
|
||||
SELECT f1(3, 100) FROM DUAL;
|
||||
SELECT f1(3, 2) FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
13
sql/field.h
13
sql/field.h
@ -3850,6 +3850,19 @@ public:
|
||||
interval_list.empty();
|
||||
}
|
||||
|
||||
Column_definition(const char *name, enum_field_types type):
|
||||
field_name(name),
|
||||
comment(null_lex_str),
|
||||
on_update(0), sql_type(type), length(0), decimals(0),
|
||||
flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE),
|
||||
interval(0), charset(&my_charset_bin),
|
||||
srid(0), geom_type(Field::GEOM_GEOMETRY),
|
||||
option_list(NULL),
|
||||
vcol_info(0), default_value(0), check_constraint(0)
|
||||
{
|
||||
interval_list.empty();
|
||||
}
|
||||
|
||||
Column_definition(THD *thd, Field *field, Field *orig_field);
|
||||
void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs);
|
||||
void create_length_to_internal_length(void);
|
||||
|
124
sql/sql_lex.cc
124
sql/sql_lex.cc
@ -2007,8 +2007,13 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
|
||||
|
||||
/* Actually real shouldn't start with . but allow them anyhow */
|
||||
case MY_LEX_REAL_OR_POINT:
|
||||
if (my_isdigit(cs,lip->yyPeek()))
|
||||
if (my_isdigit(cs,(c= lip->yyPeek())))
|
||||
state = MY_LEX_REAL; // Real
|
||||
else if (c == '.')
|
||||
{
|
||||
lip->yySkip();
|
||||
return DOT_DOT_SYM;
|
||||
}
|
||||
else
|
||||
{
|
||||
state= MY_LEX_IDENT_SEP; // return '.'
|
||||
@ -5243,6 +5248,123 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
The FOR LOOP statement
|
||||
|
||||
This syntax:
|
||||
FOR i IN lower_bound .. upper_bound
|
||||
LOOP
|
||||
statements;
|
||||
END LOOP;
|
||||
|
||||
is translated into:
|
||||
|
||||
DECLARE
|
||||
i INT := lower_bound;
|
||||
j INT := upper_bound;
|
||||
BEGIN
|
||||
WHILE i <= j
|
||||
LOOP
|
||||
statements;
|
||||
i:= i + 1;
|
||||
END LOOP;
|
||||
END;
|
||||
*/
|
||||
|
||||
|
||||
sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_STRING name,
|
||||
Item *value)
|
||||
{
|
||||
sp_variable *spvar= spcont->add_variable(thd, name);
|
||||
spcont->declare_var_boundary(1);
|
||||
spvar->field_def= Column_definition(spvar->name.str, MYSQL_TYPE_LONGLONG);
|
||||
if (sp_variable_declarations_finalize(thd, 1, spvar->field_def, value))
|
||||
return NULL;
|
||||
return spvar;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate a code for a FOR loop condition:
|
||||
- Make Item_splocal for the FOR loop index variable
|
||||
- Make Item_splocal for the FOR loop upper bound variable
|
||||
- Make a comparison function item on top of these two variables
|
||||
*/
|
||||
bool LEX::sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
Item_splocal *args[2];
|
||||
for (uint i= 0 ; i < 2; i++)
|
||||
{
|
||||
sp_variable *src= i == 0 ? loop.m_index : loop.m_upper_bound;
|
||||
args[i]= new (thd->mem_root)
|
||||
Item_splocal(thd, src->name, src->offset, src->sql_type());
|
||||
if (args[i] == NULL)
|
||||
return true;
|
||||
#ifndef DBUG_OFF
|
||||
args[i]->m_sp= sphead;
|
||||
#endif
|
||||
}
|
||||
|
||||
Item *expr= loop.m_direction > 0 ?
|
||||
(Item *) new (thd->mem_root) Item_func_le(thd, args[0], args[1]) :
|
||||
(Item *) new (thd->mem_root) Item_func_ge(thd, args[0], args[1]);
|
||||
return !expr || sp_while_loop_expression(thd, expr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate the FOR LOOP condition code in its own lex
|
||||
*/
|
||||
bool LEX::sp_for_loop_index_and_bounds(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
sphead->reset_lex(thd);
|
||||
if (thd->lex->sp_for_loop_condition(thd, loop))
|
||||
return true;
|
||||
return thd->lex->sphead->restore_lex(thd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate a code for a FOR loop index increment
|
||||
*/
|
||||
bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
Item_splocal *splocal= new (thd->mem_root)
|
||||
Item_splocal(thd, loop.m_index->name, loop.m_index->offset,
|
||||
loop.m_index->sql_type());
|
||||
if (splocal == NULL)
|
||||
return true;
|
||||
#ifndef DBUG_OFF
|
||||
splocal->m_sp= sphead;
|
||||
#endif
|
||||
Item_int *inc= new (thd->mem_root) Item_int(thd, loop.m_direction);
|
||||
if (!inc)
|
||||
return true;
|
||||
Item *expr= new (thd->mem_root) Item_func_plus(thd, splocal, inc);
|
||||
if (!expr || set_local_variable(loop.m_index, expr))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_for_loop_finalize(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
sphead->reset_lex(thd);
|
||||
|
||||
// Generate FOR LOOP index increment in its own lex
|
||||
DBUG_ASSERT(this != thd->lex);
|
||||
if (thd->lex->sp_for_loop_increment(thd, loop) ||
|
||||
thd->lex->sphead->restore_lex(thd))
|
||||
return true;
|
||||
|
||||
// Generate a jump to the beginning of the loop
|
||||
DBUG_ASSERT(this == thd->lex);
|
||||
return sp_while_loop_finalize(thd);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name, LEX *cursor_stmt)
|
||||
{
|
||||
uint offp;
|
||||
|
@ -2633,6 +2633,10 @@ private:
|
||||
bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive);
|
||||
bool sp_exit_block(THD *thd, sp_label *lab);
|
||||
bool sp_exit_block(THD *thd, sp_label *lab, Item *when);
|
||||
|
||||
bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop);
|
||||
bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop);
|
||||
|
||||
public:
|
||||
inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
|
||||
bool set_arena_for_set_stmt(Query_arena *backup);
|
||||
@ -3167,6 +3171,16 @@ public:
|
||||
bool sp_while_loop_expression(THD *thd, Item *expr);
|
||||
bool sp_while_loop_finalize(THD *thd);
|
||||
|
||||
sp_variable *sp_add_for_loop_variable(THD *thd, const LEX_STRING name,
|
||||
Item *value);
|
||||
sp_variable *sp_add_for_loop_upper_bound(THD *thd, Item *value)
|
||||
{
|
||||
LEX_STRING name= { C_STRING_WITH_LEN("[upper_bound]") };
|
||||
return sp_add_for_loop_variable(thd, name, value);
|
||||
}
|
||||
bool sp_for_loop_index_and_bounds(THD *thd, const Lex_for_loop_st &loop);
|
||||
bool sp_for_loop_finalize(THD *thd, const Lex_for_loop_st &loop);
|
||||
|
||||
// Check if "KEY IF NOT EXISTS name" used outside of ALTER context
|
||||
bool check_add_key(DDL_options_st ddl)
|
||||
{
|
||||
|
@ -803,6 +803,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
|
||||
Lex_cast_type_st Lex_cast_type;
|
||||
Lex_field_type_st Lex_field_type;
|
||||
Lex_dyncol_type_st Lex_dyncol_type;
|
||||
Lex_for_loop_st for_loop;
|
||||
|
||||
/* pointers */
|
||||
Create_field *create_field;
|
||||
@ -1060,6 +1061,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token DOUBLE_SYM /* SQL-2003-R */
|
||||
%token DO_DOMAIN_IDS_SYM
|
||||
%token DO_SYM
|
||||
%token DOT_DOT_SYM
|
||||
%token DROP /* SQL-2003-R */
|
||||
%token DUAL_SYM
|
||||
%token DUMPFILE
|
||||
|
@ -177,6 +177,7 @@ void ORAerror(THD *thd, const char *s)
|
||||
Lex_cast_type_st Lex_cast_type;
|
||||
Lex_field_type_st Lex_field_type;
|
||||
Lex_dyncol_type_st Lex_dyncol_type;
|
||||
Lex_for_loop_st for_loop;
|
||||
|
||||
/* pointers */
|
||||
Create_field *create_field;
|
||||
@ -260,10 +261,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%parse-param { THD *thd }
|
||||
%lex-param { THD *thd }
|
||||
/*
|
||||
Currently there are 102 shift/reduce conflicts.
|
||||
Currently there are 103 shift/reduce conflicts.
|
||||
We should not introduce new conflicts any more.
|
||||
*/
|
||||
%expect 102
|
||||
%expect 103
|
||||
|
||||
/*
|
||||
Comments for TOKENS.
|
||||
@ -434,6 +435,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token DOUBLE_SYM /* SQL-2003-R */
|
||||
%token DO_DOMAIN_IDS_SYM
|
||||
%token DO_SYM
|
||||
%token DOT_DOT_SYM
|
||||
%token DROP /* SQL-2003-R */
|
||||
%token DUAL_SYM
|
||||
%token DUMPFILE
|
||||
@ -1278,6 +1280,8 @@ END_OF_INPUT
|
||||
%type <lex> sp_cursor_stmt
|
||||
%type <spname> sp_name
|
||||
%type <spvar> sp_param_name sp_param_name_and_type
|
||||
%type <for_loop> sp_for_loop_index_and_bounds
|
||||
%type <num> opt_sp_for_loop_direction
|
||||
%type <spvar_mode> sp_opt_inout
|
||||
%type <index_hint> index_hint_type
|
||||
%type <num> index_hint_clause normal_join inner_join
|
||||
@ -3471,6 +3475,32 @@ exception_handler:
|
||||
}
|
||||
;
|
||||
|
||||
/* This adds one shift/reduce conflict */
|
||||
opt_sp_for_loop_direction:
|
||||
/* Empty */ { $$= 1; }
|
||||
| REVERSE_SYM { $$= -1; }
|
||||
;
|
||||
|
||||
sp_for_loop_index_and_bounds:
|
||||
ident_directly_assignable
|
||||
{
|
||||
Lex->sphead->reset_lex(thd);
|
||||
}
|
||||
IN_SYM opt_sp_for_loop_direction expr
|
||||
{
|
||||
if (!($<spvar>$= Lex->sp_add_for_loop_variable(thd, $1, $5)))
|
||||
MYSQL_YYABORT;
|
||||
Lex->sphead->reset_lex(thd);
|
||||
}
|
||||
DOT_DOT_SYM expr
|
||||
{
|
||||
$$.m_index= $<spvar>6;
|
||||
if (!($$.m_upper_bound= Lex->sp_add_for_loop_upper_bound(thd, $8)))
|
||||
MYSQL_YYABORT;
|
||||
$$.m_direction= $4;
|
||||
}
|
||||
;
|
||||
|
||||
loop_body:
|
||||
sp_proc_stmts1 END LOOP_SYM
|
||||
{
|
||||
@ -3574,6 +3604,28 @@ sp_unlabeled_control:
|
||||
{
|
||||
Lex->sp_pop_loop_empty_label(thd);
|
||||
}
|
||||
| FOR_SYM
|
||||
{
|
||||
// See "The FOR LOOP statement" comments in sql_lex.cc
|
||||
Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
|
||||
}
|
||||
sp_for_loop_index_and_bounds
|
||||
{
|
||||
if (Lex->sp_push_loop_empty_label(thd)) // The inner WHILE block
|
||||
MYSQL_YYABORT;
|
||||
if (Lex->sp_for_loop_index_and_bounds(thd, $3))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
LOOP_SYM
|
||||
sp_proc_stmts1
|
||||
END LOOP_SYM
|
||||
{
|
||||
if (Lex->sp_for_loop_finalize(thd, $3))
|
||||
MYSQL_YYABORT;
|
||||
Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block
|
||||
if (Lex->sp_block_finalize(thd)) // The outer DECLARE..BEGIN..END
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| REPEAT_SYM
|
||||
{
|
||||
if (Lex->sp_push_loop_empty_label(thd))
|
||||
|
@ -668,4 +668,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Lex_for_loop_st
|
||||
{
|
||||
public:
|
||||
class sp_variable *m_index;
|
||||
class sp_variable *m_upper_bound;
|
||||
int m_direction;
|
||||
};
|
||||
|
||||
|
||||
#endif /* STRUCTS_INCLUDED */
|
||||
|
Reference in New Issue
Block a user