!2055 兼容mysql语法“label: loop”
Merge pull request !2055 from qx21/feature/loop_old
This commit is contained in:
@ -479,7 +479,9 @@ static bool need_build_row_for_func_arg(PLpgSQL_rec **rec, PLpgSQL_row **row, in
|
||||
%token <keyword> K_INTERSECT
|
||||
%token <keyword> K_INTO
|
||||
%token <keyword> K_IS
|
||||
%token <keyword> K_ITERATE
|
||||
%token <keyword> K_LAST
|
||||
%token <keyword> K_LEAVE
|
||||
%token <keyword> K_LIMIT
|
||||
%token <keyword> K_LOG
|
||||
%token <keyword> K_LOOP
|
||||
@ -2731,6 +2733,32 @@ stmt_loop : opt_block_label K_LOOP loop_body
|
||||
/* register the stmt if it is labeled */
|
||||
record_stmt_label($1, (PLpgSQL_stmt *)newp);
|
||||
}
|
||||
| ':' K_LOOP loop_body
|
||||
{
|
||||
/*
|
||||
* When the database is in mysql compatible mode
|
||||
* support "label: loop"
|
||||
*/
|
||||
if(u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("'label:' is only supported in database which dbcompatibility='B'.")));
|
||||
|
||||
PLpgSQL_stmt_loop *newp;
|
||||
newp = (PLpgSQL_stmt_loop *)palloc0(sizeof(PLpgSQL_stmt_loop));
|
||||
newp->cmd_type = PLPGSQL_STMT_LOOP;
|
||||
newp->lineno = plpgsql_location_to_lineno(@2);
|
||||
newp->label = u_sess->plsql_cxt.curr_compile_context->ns_top->name;
|
||||
newp->body = $3.stmts;
|
||||
newp->sqlString = plpgsql_get_curline_query();
|
||||
|
||||
check_labels(u_sess->plsql_cxt.curr_compile_context->ns_top->name, $3.end_label, $3.end_label_location);
|
||||
plpgsql_ns_pop();
|
||||
|
||||
$$ = (PLpgSQL_stmt *)newp;
|
||||
|
||||
/* register the stmt if it is labeled */
|
||||
record_stmt_label(u_sess->plsql_cxt.curr_compile_context->ns_top->name, (PLpgSQL_stmt *)newp);
|
||||
}
|
||||
;
|
||||
|
||||
stmt_while : opt_block_label K_WHILE expr_until_loop loop_body
|
||||
@ -3530,6 +3558,30 @@ exit_type : K_EXIT
|
||||
}
|
||||
| K_CONTINUE
|
||||
{
|
||||
$$ = false;
|
||||
}
|
||||
| K_LEAVE
|
||||
{
|
||||
/*
|
||||
* When the database is in mysql compatible mode
|
||||
* support "leave label"
|
||||
*/
|
||||
if(u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("'LEAVE label' is only in database which dbcompatibility='B'.")));
|
||||
|
||||
$$ = true;
|
||||
}
|
||||
| K_ITERATE
|
||||
{
|
||||
/*
|
||||
* When the database is in mysql compatible mode
|
||||
* support "iterate label"
|
||||
*/
|
||||
if(u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("'ITERATE label' is only in database which dbcompatibility='B'.")));
|
||||
|
||||
$$ = false;
|
||||
}
|
||||
;
|
||||
@ -8473,7 +8525,7 @@ make_execsql_stmt(int firsttoken, int location)
|
||||
int parenlevel = 0;
|
||||
List *list_bracket = 0; /* stack structure bracket tracker */
|
||||
List *list_bracket_loc = 0; /* location tracker */
|
||||
|
||||
bool label_loop = false;
|
||||
initStringInfo(&ds);
|
||||
|
||||
/* special lookup mode for identifiers within the SQL text */
|
||||
@ -8586,6 +8638,55 @@ make_execsql_stmt(int firsttoken, int location)
|
||||
u_sess->plsql_cxt.curr_compile_context->plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the database is in mysql compatible mode,
|
||||
* the loop syntax of mysql is compatible (label: loop)
|
||||
*/
|
||||
if (tok == ':' && prev_tok == T_WORD)
|
||||
{
|
||||
StringInfoData lb;
|
||||
initStringInfo(&lb);
|
||||
int lb_end = yylloc;
|
||||
int tok1 = yylex();
|
||||
if(tok1 == K_LOOP)
|
||||
{
|
||||
if(u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
|
||||
{
|
||||
int count = 0;
|
||||
label_loop = true;
|
||||
plpgsql_push_back_token(tok1);
|
||||
plpgsql_push_back_token(tok);
|
||||
plpgsql_append_source_text(&lb, location, lb_end);
|
||||
|
||||
for(int i = lb.len-1; i > 0; i--)
|
||||
{
|
||||
if(lb.data[i] == ' ')
|
||||
{
|
||||
count++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(count > 0)
|
||||
{
|
||||
char* name = (char*)palloc(lb.len-count+1);
|
||||
strncpy(name, lb.data, lb.len-count);
|
||||
name[lb.len-count] = '\0';
|
||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, pg_strtolower(name));
|
||||
pfree(name);
|
||||
}
|
||||
else
|
||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, pg_strtolower(lb.data));
|
||||
|
||||
pfree_ext(lb.data);
|
||||
break;
|
||||
}
|
||||
else
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("'label:' is only supported in database which dbcompatibility='B'.")));
|
||||
}
|
||||
}
|
||||
|
||||
if (tok == T_CWORD && prev_tok!=K_SELECT
|
||||
&& prev_tok!= K_PERFORM) {
|
||||
List *dtname = yylval.cword.idents;
|
||||
@ -8870,6 +8971,9 @@ make_execsql_stmt(int firsttoken, int location)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (label_loop)
|
||||
{
|
||||
appendStringInfoString(&ds, "\n");
|
||||
} else {
|
||||
plpgsql_append_source_text(&ds, location, yylloc);
|
||||
|
||||
|
||||
@ -142,8 +142,10 @@ static const ScanKeyword unreserved_keywords[] = {
|
||||
PG_KEYWORD("info", K_INFO, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("instantiation", K_INSTANTIATION, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("intersect", K_INTERSECT, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("iterate", K_ITERATE, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("last", K_LAST, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("leave", K_LEAVE, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("log", K_LOG, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("merge", K_MERGE, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("message", K_MESSAGE, UNRESERVED_KEYWORD)
|
||||
|
||||
@ -916,6 +916,273 @@ SELECT * FROM view_schema.new_view3;
|
||||
|
||||
RESET ROLE;
|
||||
\c regression
|
||||
-- test label:loop
|
||||
--error
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
label1: loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
ERROR: 'label:' is only supported in database which dbcompatibility='B'.
|
||||
CONTEXT: compilation of PL/pgSQL function "doiterate" near line 1
|
||||
--error
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
<<label1>> loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
ERROR: 'ITERATE label' is only in database which dbcompatibility='B'.
|
||||
CONTEXT: compilation of PL/pgSQL function "doiterate" near line 4
|
||||
--error
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
<<label1>> loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
continue label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
ERROR: 'LEAVE label' is only in database which dbcompatibility='B'.
|
||||
CONTEXT: compilation of PL/pgSQL function "doiterate" near line 5
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
<<label1>> loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
continue label1;
|
||||
end if;
|
||||
exit label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
call doiterate(3);
|
||||
NOTICE: p1:10
|
||||
doiterate
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
drop procedure if exists doiterate;
|
||||
\c b
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
label1 :
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
raise notice '123';
|
||||
end if;
|
||||
exit;
|
||||
end loop label1;
|
||||
end;
|
||||
/
|
||||
call doiterate(2);
|
||||
NOTICE: 123
|
||||
doiterate
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
LABEL1:
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
raise notice '123';
|
||||
end if;
|
||||
exit LABEL1;
|
||||
end loop LABEL1;
|
||||
end;
|
||||
/
|
||||
call doiterate(2);
|
||||
NOTICE: 123
|
||||
doiterate
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
LAbEL1:
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
raise notice '123';
|
||||
end if;
|
||||
exit LABeL1;
|
||||
end loop LaBEL1;
|
||||
end;
|
||||
/
|
||||
call doiterate(2);
|
||||
NOTICE: 123
|
||||
doiterate
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
label1: loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
call doiterate(3);
|
||||
NOTICE: p1:10
|
||||
doiterate
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate;
|
||||
end if;
|
||||
leave;
|
||||
end loop;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
call doiterate(3);
|
||||
NOTICE: p1:10
|
||||
doiterate
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
label1: loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
call labeltest(5);
|
||||
labeltest
|
||||
-----------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
LABEL1: loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate LABEL1;
|
||||
end if;
|
||||
leave LABEL1;
|
||||
end loop LABEL1;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
call labeltest(3);
|
||||
labeltest
|
||||
-----------
|
||||
3
|
||||
(1 row)
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
lAbel1: loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate labEl1;
|
||||
end if;
|
||||
leave LAbel1;
|
||||
end loop labEL1;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
call labeltest(7);
|
||||
labeltest
|
||||
-----------
|
||||
7
|
||||
(1 row)
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate;
|
||||
end if;
|
||||
leave;
|
||||
end loop;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
call labeltest(9);
|
||||
labeltest
|
||||
-----------
|
||||
9
|
||||
(1 row)
|
||||
|
||||
drop procedure if exists doiterate;
|
||||
drop function if exists labeltest;
|
||||
\c regression
|
||||
drop database b;
|
||||
DROP USER test_c;
|
||||
DROP USER test_d;
|
||||
|
||||
@ -289,6 +289,235 @@ RESET ROLE;
|
||||
|
||||
\c regression
|
||||
|
||||
-- test label:loop
|
||||
--error
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
label1: loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
|
||||
--error
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
<<label1>> loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
|
||||
--error
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
<<label1>> loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
continue label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
<<label1>> loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
continue label1;
|
||||
end if;
|
||||
exit label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
|
||||
call doiterate(3);
|
||||
|
||||
drop procedure if exists doiterate;
|
||||
\c b
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
label1 :
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
raise notice '123';
|
||||
end if;
|
||||
exit;
|
||||
end loop label1;
|
||||
end;
|
||||
/
|
||||
|
||||
call doiterate(2);
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
LABEL1:
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
raise notice '123';
|
||||
end if;
|
||||
exit LABEL1;
|
||||
end loop LABEL1;
|
||||
end;
|
||||
/
|
||||
|
||||
call doiterate(2);
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
LAbEL1:
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
raise notice '123';
|
||||
end if;
|
||||
exit LABeL1;
|
||||
end loop LaBEL1;
|
||||
end;
|
||||
/
|
||||
|
||||
call doiterate(2);
|
||||
|
||||
--success
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
label1: loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
|
||||
call doiterate(3);
|
||||
|
||||
create or replace procedure doiterate(p1 int)
|
||||
as
|
||||
begin
|
||||
loop
|
||||
p1 := p1+1;
|
||||
if p1 < 10 then
|
||||
iterate;
|
||||
end if;
|
||||
leave;
|
||||
end loop;
|
||||
raise notice 'p1:%',p1;
|
||||
end;
|
||||
/
|
||||
|
||||
call doiterate(3);
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
label1: loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate label1;
|
||||
end if;
|
||||
leave label1;
|
||||
end loop label1;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
|
||||
call labeltest(5);
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
LABEL1: loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate LABEL1;
|
||||
end if;
|
||||
leave LABEL1;
|
||||
end loop LABEL1;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
|
||||
call labeltest(3);
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
lAbel1: loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate labEl1;
|
||||
end if;
|
||||
leave LAbel1;
|
||||
end loop labEL1;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
|
||||
call labeltest(7);
|
||||
|
||||
create or replace function labeltest(n int) return int
|
||||
as
|
||||
p int;
|
||||
i int;
|
||||
begin
|
||||
p :=2;
|
||||
loop
|
||||
if p < n then
|
||||
p := p+1;
|
||||
iterate;
|
||||
end if;
|
||||
leave;
|
||||
end loop;
|
||||
return p;
|
||||
end;
|
||||
/
|
||||
|
||||
call labeltest(9);
|
||||
drop procedure if exists doiterate;
|
||||
drop function if exists labeltest;
|
||||
|
||||
\c regression
|
||||
|
||||
drop database b;
|
||||
DROP USER test_c;
|
||||
DROP USER test_d;
|
||||
|
||||
Reference in New Issue
Block a user