为提高效率,请提供以下信息,问题描述清晰能够更快得到解决:
【概述】 场景 + 问题概述
我尝试在对 parser 进行修改,希望其能支持对 function 的解析,在解析部分 sql 的时候有些疑惑,请各位大佬指教。
【parser 版本】
v4.0.2
【步骤】
/********************************************************************
* Create Function Statement
*
* CREATE
* [DEFINER = user]
* FUNCTION sp_name ([func_parameter[,...]])
* RETURNS type
* [characteristic ...] routine_body
*
* func_parameter:
* param_name type
*
* type:
* Any valid MySQL data type
*
* characteristic: {
* COMMENT 'string'
* | LANGUAGE SQL
* | [NOT] DETERMINISTIC
* | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
* | SQL SECURITY { DEFINER | INVOKER }
* }
*
* routine_body:
* Valid SQL routine statement
*
* Ref:
* https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html
*******************************************************************/
CreateFunctionStmt:
"CREATE" "FUNCTION" FunctionName FunctionParameterOpt ReturnDataOpt CharacteristicOptionList
{
x := &ast.CreateFunctionStmt{
Name: $3.(*ast.TableName),
Args: $4.([]*ast.ColumnDef),
Rtp: $5.(*types.FieldType),
}
if $6 != nil {
x.Characteristic = $6.(*ast.CharacteristicOption)
}
$$ = x
}
CharacteristicOptionList:
/* empty */
{
$$ = nil
}
| CharacteristicOptionList CharacteristicOption
{
// Merge the options
if $1 == nil {
$$ = $2
} else {
opt1 := $1.(*ast.CharacteristicOption)
opt2 := $1.(*ast.CharacteristicOption)
if len(opt2.Comment) > 0 {
opt1.Comment = opt2.Comment
} else if opt2.Deterministic != opt1.Deterministic {
opt1.Deterministic = opt2.Deterministic
} else if opt2.Security != opt1.Security {
opt1.Security = opt2.Security
}
$$ = opt1
}
}
CharacteristicOption:
{
$$ = nil
}
| "COMMENT" stringLit
{
$$ = &ast.CharacteristicOption{
Comment: $2,
}
}
| DeterministicOrNotOp
{
$$ = &ast.CharacteristicOption{
Deterministic: $1.(bool),
}
}
| ViewSQLSecurity
{
$$ = &ast.CharacteristicOption{
Security: $1.(model.ViewSecurity),
}
}
DeterministicOrNotOp:
"DETERMINISTIC"
{
$$ = true
}
| "NOT" "DETERMINISTIC"
{
$$ = false
}
FunctionName:
TableName
FunctionParameterOpt:
/* empty */
{
$$ = make([]*ast.ColumnDef, 0, 1)
}
| '(' FunctionColumnDefList ')'
{
$$ = $2.([]*ast.ColumnDef)
}
FunctionColumnDefList:
FunctionColumnDef
{
$$ = []*ast.ColumnDef{$1.(*ast.ColumnDef)}
}
| FunctionColumnDefList ',' FunctionColumnDef
{
$$ = append($1.([]*ast.ColumnDef), $3.(*ast.ColumnDef))
}
FunctionColumnDef:
ColumnName Type
{
colDef := &ast.ColumnDef{Name: $1.(*ast.ColumnName), Tp: $2.(*types.FieldType)}
$$ = colDef
}
ReturnDataOpt:
"RETURNS" Type
{
$$ = $2.(*types.FieldType)
}
ddl.go 中代码如下
// CreateFunctionStmt is a statement to create a Function.
type CreateFunctionStmt struct {
ddlNode
IfNotExists bool
Name *TableName
Args []*ColumnDef
Rtp *types.FieldType
Characteristic *CharacteristicOption
}
// Restore implements Node interface.
func (n *CreateFunctionStmt) Restore(ctx *format.RestoreCtx) error {
ctx.WriteKeyWord("CREATE ")
ctx.WriteKeyWord("FUNCTION ")
if n.IfNotExists {
ctx.WriteKeyWord("IF NOT EXISTS ")
}
if err := n.Name.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while create CreateFunctionStmt.Name")
}
if len(n.Args) > 0 {
ctx.WritePlain("(")
for i, col := range n.Args {
if i > 0 {
ctx.WritePlain(",")
}
if err := col.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while splicing CreateFunctionStmt Args: [%v]", i)
}
}
ctx.WritePlain(")")
}
ctx.WritePlain(" RETURNS ")
if err := n.Rtp.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while splicing CreateFunctionStmt Rtp: [%v]", n.Rtp)
}
if n.Characteristic != nil {
ctx.WritePlain(" ")
if err := n.Characteristic.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while splicing CreateFunctionStmt Characteristic: [%v]", n.Characteristic)
}
}
return nil
}
// Accept implements Node Accept interface.
func (n *CreateFunctionStmt) Accept(v Visitor) (Node, bool) {
newNode, skipChildren := v.Enter(n)
if skipChildren {
return v.Leave(newNode)
}
n = newNode.(*CreateFunctionStmt)
node, ok := n.Name.Accept(v)
if !ok {
return n, false
}
n.Name = node.(*TableName)
return v.Leave(n)
}
// CharacteristicOption ...
// CharacteristicOption for function or procedure
type CharacteristicOption struct {
node
Comment string
Deterministic bool
Security model.ViewSecurity
}
// Accept implements Node Accept interface.
// Accept implements Node Accept interface.
func (n *CharacteristicOption) Accept(v Visitor) (Node, bool) {
newNode, skipChildren := v.Enter(n)
if skipChildren {
return v.Leave(newNode)
}
n = newNode.(*CharacteristicOption)
return v.Leave(n)
}
// Restore implements Node interface.
func (n *CharacteristicOption) Restore(ctx *format.RestoreCtx) error {
hasPrevOption := false
if n.Comment != "" {
if hasPrevOption {
ctx.WritePlain(" ")
}
ctx.WriteKeyWord("COMMENT ")
ctx.WriteString(n.Comment)
hasPrevOption = true
}
if n.Deterministic {
if hasPrevOption {
ctx.WritePlain(" ")
}
ctx.WriteKeyWord("DETERMINISTIC")
hasPrevOption = true
} else {
if hasPrevOption {
ctx.WritePlain(" ")
}
ctx.WriteKeyWord("NOT DETERMINISTIC")
hasPrevOption = true
}
ctx.WriteKeyWord(" SQL SECURITY ")
ctx.WriteKeyWord(n.Security.String())
return nil
}
在执行 make 的时候,出现了
make
gofmt (simplify)
bin/goyacc -o parser.go -p yy -t Parser parser.y
conflicts: 4 shift/reduce
conflicts: 6 reduce/reduce
请问,我该怎么处理 CharacteristicOptionList 这个值?