Skip to content

Commit

Permalink
sql: stmt_call, stmt_close, stmt_dynaexec, stmt_exit
Browse files Browse the repository at this point in the history
This commit adds the AST and grammar rules for `stmt_call`,
`stmt_close`, `stmt_dynaexec`, and `stmt_exit`

Release note: None
  • Loading branch information
chengxiong-ruan authored and e-mbrown committed May 10, 2023
1 parent 6820fdb commit 6cd98d9
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 19 deletions.
46 changes: 46 additions & 0 deletions pkg/sql/plpgsql/parser/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,52 @@ func (l *lexer) MakeExecSqlStmt(startTokenID int) *plpgsqltree.PLpgSQLStmtExecSq
}
}

func (l *lexer) MakeDynamicExecuteStmt() *plpgsqltree.PLpgSQLStmtDynamicExecute {
cmdStr, _ := l.ReadSqlConstruct(INTO, USING, ';')
ret := &plpgsqltree.PLpgSQLStmtDynamicExecute{
Query: cmdStr,
}

var lval plpgsqlSymType
l.Lex(&lval)
for {
if lval.id == INTO {
if ret.Into {
errors.AssertionFailedf("seen multiple INTO")
}
ret.Into = true
nextTok := l.Peek()
if nextTok.id == int32(STRICT) {
l.Lex(&lval)
ret.Strict = true
}
// TODO we need to read each "INTO" variable name instead of just a
// string.
l.ReadSqlExpressionStr2(USING, ';')
l.Lex(&lval)
} else if lval.id == USING {
if ret.Params != nil {
errors.AssertionFailedf("seen multiple USINGs")
}
ret.Params = make([]plpgsqltree.PLpgSQLExpr, 0)
for {
l.ReadSqlConstruct(',', ';', INTO)
ret.Params = append(ret.Params, nil)
l.Lex(&lval)
if lval.id == ';' {
break
}
}
} else if lval.id == ';' {
break
} else {
errors.AssertionFailedf("syntax error")
}
}

return ret
}

// ReadSqlExpressionStr returns the string from the l.lastPos till it sees
// the terminator for the first time. The returned string is made by tokens
// between the starting index (included) to the terminator (not included).
Expand Down
3 changes: 1 addition & 2 deletions pkg/sql/plpgsql/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ import (
func TestParseDeclareSection(t *testing.T) {
fn := `
DECLARE
ASSERT 1 > 2;
ASSERT 1 > 2 'error message' ;
BEGIN
EXECUTE 'any command' INTO x1 USING x2;
END`
stmt, err := parser.Parse(fn)
require.NoError(t, err)
Expand Down
33 changes: 18 additions & 15 deletions pkg/sql/plpgsql/parser/plpgsql.y
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func (u *plpgsqlSymUnion) pLpgSQLStmtOpen() *plpgsqltree.PLpgSQLStmtOpen {
%type <[]plpgsqltree.PLpgSQLStatement> proc_sect
%type <[]plpgsqltree.PLpgSQLStatement> stmt_elsifs stmt_else // TODO is this a list of statement?
%type <loopBody> loop_body
%type <plpgsqltree.PLpgSQLStatement> pl_block
%type <plpgsqltree.PLpgSQLStatement> pl_block
%type <plpgsqltree.PLpgSQLStatement> proc_stmt
%type <plpgsqltree.PLpgSQLStatement> stmt_assign stmt_if stmt_loop stmt_while stmt_exit
%type <plpgsqltree.PLpgSQLStatement> stmt_return stmt_raise stmt_assert stmt_execsql
Expand Down Expand Up @@ -595,15 +595,20 @@ stmt_perform : PERFORM
}
;

stmt_call : CALL ';'
stmt_call : CALL call_cmd ';'
{
$$.val = &plpgsqltree.PLpgSQLStmtCall{IsCall: true}
}
| DO ';'
| DO call_cmd ';'
{
$$.val = &plpgsqltree.PLpgSQLStmtCall{IsCall: false}
}
;
call_cmd:
{
plpgsqllex.(*lexer).ReadSqlExpressionStr(';')
}
;

stmt_assign : T_DATUM
{
Expand Down Expand Up @@ -857,14 +862,10 @@ stmt_execsql : IMPORT
}
;

// TODO(chengxiong): we should parse a valid expression, INTO and USING keywords
// instead of just match random symbols.
stmt_dynexecute : EXECUTE ';'
{
$$.val = &plpgsqltree.PLpgSQLStmtDynamicExecute{}
}
;

stmt_dynexecute : EXECUTE
{
$$.val = plpgsqllex.(*lexer).MakeDynamicExecuteStmt()}
;

stmt_open : OPEN cursor_variable
{
Expand Down Expand Up @@ -954,9 +955,11 @@ proc_condition : any_identifier
}
;

expr_until_semi : ';'
{ }
;
expr_until_semi :
{
plpgsqllex.(*lexer).ReadSqlExpressionStr(';')
}
;

expr_until_then :
{
Expand Down Expand Up @@ -996,7 +999,7 @@ opt_label :

opt_exitcond : ';'
{ }
| WHEN expr_until_semi
| WHEN expr_until_semi ';'
{ }
;

Expand Down
12 changes: 12 additions & 0 deletions pkg/sql/plpgsql/parser/testdata/stmt_call
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
parse
DECLARE
BEGIN
CALL fn(1);
DO $$ this is a code block $$;
END
----
DECLARE
BEGIN
CALL a function/procedure
DO a code block
END
10 changes: 10 additions & 0 deletions pkg/sql/plpgsql/parser/testdata/stmt_close
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
parse
DECLARE
BEGIN
CLOSE some_cursor;
END
----
DECLARE
BEGIN
CLOSE a cursor
END
54 changes: 54 additions & 0 deletions pkg/sql/plpgsql/parser/testdata/stmt_dynexec
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
parse
DECLARE
BEGIN
EXECUTE 'any command';
END
----
DECLARE
BEGIN
EXECUTE a dynamic command
END

parse
DECLARE
BEGIN
EXECUTE 'any command' INTO x1;
END
----
DECLARE
BEGIN
EXECUTE a dynamic command WITH INTO
END

parse
DECLARE
BEGIN
EXECUTE 'any command' INTO STRICT x1;
END
----
DECLARE
BEGIN
EXECUTE a dynamic command WITH INTO STRICT
END

parse
DECLARE
BEGIN
EXECUTE 'any command' INTO x1 USING x2;
END
----
DECLARE
BEGIN
EXECUTE a dynamic command WITH INTO WITH USING
END

parse
DECLARE
BEGIN
EXECUTE 'any command' INTO x1, x2 USING y1, y2;
END
----
DECLARE
BEGIN
EXECUTE a dynamic command WITH INTO WITH USING
END
12 changes: 12 additions & 0 deletions pkg/sql/plpgsql/parser/testdata/stmt_exit
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
parse
DECLARE
BEGIN
EXIT some_label;
EXIT some_label WHEN some_condition;
END
----
DECLARE
BEGIN
EXIT
EXIT
END
16 changes: 14 additions & 2 deletions pkg/sql/sem/plpgsqltree/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package plpgsqltree

import (
"fmt"

"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
)

Expand Down Expand Up @@ -305,17 +306,28 @@ func (s *PLpgSQLStmtExecSql) Format(ctx *tree.FmtCtx) {
}

// stmt_dynexecute
// TODO(chengxiong): query should be a better expression type.
type PLpgSQLStmtDynamicExecute struct {
PLpgSQLStatementImpl
Query PLpgSQLExpr
Query string
Into bool
Strict bool
Target PLpgSQLVariable
Params []PLpgSQLExpr
}

func (s *PLpgSQLStmtDynamicExecute) Format(ctx *tree.FmtCtx) {
ctx.WriteString("EXECUTE a dynamic command\n")
ctx.WriteString("EXECUTE a dynamic command")
if s.Into {
ctx.WriteString(" WITH INTO")
if s.Strict {
ctx.WriteString(" STRICT")
}
}
if s.Params != nil {
ctx.WriteString(" WITH USING")
}
ctx.WriteString("\n")
}

// stmt_perform
Expand Down

0 comments on commit 6cd98d9

Please sign in to comment.