!2055 兼容mysql语法“label: loop”

Merge pull request !2055 from qx21/feature/loop_old
This commit is contained in:
opengauss-bot
2022-09-01 13:25:25 +00:00
committed by Gitee
4 changed files with 604 additions and 2 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;