Skip to content

Commit 57ebce9

Browse files
author
James Cor
committed
lots of fixing towards validation
1 parent f755beb commit 57ebce9

File tree

1 file changed

+112
-4
lines changed

1 file changed

+112
-4
lines changed

sql/planbuilder/create_ddl.go

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ func (b *Builder) buildCreateProcedure(inScope *scope, subQuery string, fullQuer
202202
db = b.currentDb()
203203
}
204204

205+
b.validateCreateProcedure(inScope, subQuery)
206+
205207
now := time.Now()
206208
spd := sql.StoredProcedureDetails{
207209
Name: strings.ToLower(c.ProcedureSpec.ProcName.Name.String()),
@@ -213,17 +215,123 @@ func (b *Builder) buildCreateProcedure(inScope *scope, subQuery string, fullQuer
213215

214216
bodyStr := strings.TrimSpace(fullQuery[c.SubStatementPositionStart:c.SubStatementPositionEnd])
215217

216-
// TODO: need to validate limit clauses for non-integers???
217-
// TODO only return some errors??? somehow
218-
BuildProcedureHelper(b.ctx, b.cat, true, inScope.push(), db, nil, spd)
219-
218+
// TODO: need to validate limit clauses for non-integers, but not other bugs
220219
// TODO: validate for recursion and other ddl here
221220

222221
outScope = inScope.push()
223222
outScope.node = plan.NewCreateProcedure(db, spd, bodyStr)
224223
return outScope
225224
}
226225

226+
func (b *Builder) validateBlock(inScope *scope, stmts ast.Statements) {
227+
for _, s := range stmts {
228+
switch s.(type) {
229+
case *ast.Declare:
230+
default:
231+
if inScope.procActive() {
232+
inScope.proc.NewState(dsBody)
233+
}
234+
}
235+
b.validateStatement(inScope, s)
236+
}
237+
}
238+
239+
func (b *Builder) validateStatement(inScope *scope, stmt ast.Statement) {
240+
switch s := stmt.(type) {
241+
case *ast.DDL:
242+
b.handleErr(fmt.Errorf("DDL in CREATE PROCEDURE not yet supported"))
243+
case *ast.Declare:
244+
if s.Condition != nil {
245+
inScope.proc.AddCondition(plan.NewDeclareCondition(s.Condition.Name, 0, ""))
246+
} else if s.Variables != nil {
247+
typ, err := types.ColumnTypeToType(&s.Variables.VarType)
248+
if err != nil {
249+
b.handleErr(err)
250+
}
251+
for _, v := range s.Variables.Names {
252+
varName := strings.ToLower(v.String())
253+
param := expression.NewProcedureParam(varName, typ)
254+
inScope.proc.AddVar(param)
255+
inScope.newColumn(scopeColumn{col: varName, typ: typ, scalar: param})
256+
}
257+
} else if s.Cursor != nil {
258+
inScope.proc.AddCursor(s.Cursor.Name)
259+
} else if s.Handler != nil {
260+
switch s.Handler.ConditionValues[0].ValueType {
261+
case ast.DeclareHandlerCondition_NotFound:
262+
case ast.DeclareHandlerCondition_SqlException:
263+
default:
264+
err := sql.ErrUnsupportedSyntax.New(ast.String(s))
265+
b.handleErr(err)
266+
}
267+
inScope.proc.AddHandler(nil)
268+
}
269+
case *ast.BeginEndBlock:
270+
blockScope := inScope.push()
271+
blockScope.initProc()
272+
blockScope.proc.AddLabel(s.Label, false)
273+
b.validateBlock(blockScope, s.Statements)
274+
case *ast.Loop:
275+
blockScope := inScope.push()
276+
blockScope.initProc()
277+
blockScope.proc.AddLabel(s.Label, true)
278+
b.validateBlock(blockScope, s.Statements)
279+
case *ast.Repeat:
280+
blockScope := inScope.push()
281+
blockScope.initProc()
282+
blockScope.proc.AddLabel(s.Label, true)
283+
b.validateBlock(blockScope, s.Statements)
284+
case *ast.While:
285+
blockScope := inScope.push()
286+
blockScope.initProc()
287+
blockScope.proc.AddLabel(s.Label, true)
288+
b.validateBlock(blockScope, s.Statements)
289+
case *ast.IfStatement:
290+
for _, cond := range s.Conditions {
291+
b.validateBlock(inScope, cond.Statements)
292+
}
293+
if s.Else != nil {
294+
b.validateBlock(inScope, s.Else)
295+
}
296+
case *ast.Iterate:
297+
if exists, isLoop := inScope.proc.HasLabel(s.Label); !exists || !isLoop {
298+
err := sql.ErrLoopLabelNotFound.New("ITERATE", s.Label)
299+
b.handleErr(err)
300+
}
301+
case *ast.Signal:
302+
if s.ConditionName != "" {
303+
signalName := strings.ToLower(s.ConditionName)
304+
condition := inScope.proc.GetCondition(signalName)
305+
if condition == nil {
306+
err := sql.ErrDeclareConditionNotFound.New(signalName)
307+
b.handleErr(err)
308+
}
309+
}
310+
}
311+
}
312+
313+
func (b *Builder) validateCreateProcedure(inScope *scope, createStmt string) {
314+
stmt, _, _, _ := b.parser.ParseWithOptions(b.ctx, createStmt, ';', false, b.parserOpts)
315+
procStmt := stmt.(*ast.DDL)
316+
317+
// validate parameters
318+
procParams := b.buildProcedureParams(procStmt.ProcedureSpec.Params)
319+
paramNames := make(map[string]struct{})
320+
for _, param := range procParams {
321+
paramName := strings.ToLower(param.Name)
322+
if _, ok := paramNames[paramName]; ok {
323+
b.handleErr(sql.ErrDeclareVariableDuplicate.New(paramName))
324+
}
325+
paramNames[param.Name] = struct{}{}
326+
}
327+
// TODO: add params to tmpScope?
328+
329+
bodyStmt := procStmt.ProcedureSpec.Body
330+
b.validateStatement(inScope, bodyStmt)
331+
332+
// TODO: check for limit clauses that are not integers
333+
}
334+
227335
func (b *Builder) buildCreateEvent(inScope *scope, subQuery string, fullQuery string, c *ast.DDL) (outScope *scope) {
228336
outScope = inScope.push()
229337
eventSpec := c.EventSpec

0 commit comments

Comments
 (0)