Skip to content

Commit

Permalink
Merge pull request #12 from ColdWaterLW/support-1746
Browse files Browse the repository at this point in the history
Support 1746
  • Loading branch information
sjjian authored Aug 23, 2023
2 parents 3163799 + d7804d9 commit ec9bc09
Show file tree
Hide file tree
Showing 28 changed files with 6,202 additions and 4 deletions.
14 changes: 11 additions & 3 deletions ast/context.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package ast

import "fmt"

type Context struct {
QueryType string // select, insert, update, delete
Variable map[string]string
Sqls map[string]*SqlNode
QueryType string // select, insert, update, delete
Variable map[string]string
Sqls map[string]*SqlNode
DefaultNamespace string // namespace of current mapper
}

func NewContext() *Context {
Expand All @@ -24,5 +27,10 @@ func (c *Context) SetVariable(k, v string) {

func (c *Context) GetSql(k string) (*SqlNode, bool) {
sql, ok := c.Sqls[k]
if ok {
return sql, true
}
// 当存在跨namespace引用时,需要通过namespace区分引用的SQL id
sql, ok = c.Sqls[fmt.Sprintf("%v.%v", c.DefaultNamespace, k)]
return sql, ok
}
5 changes: 4 additions & 1 deletion ast/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ func (m *Mapper) GetStmt(ctx *Context) (string, error) {

func (m *Mapper) GetStmts(ctx *Context, skipErrorQuery bool) ([]string, error) {
var stmts []string
ctx.Sqls = m.SqlNodes
if len(ctx.Sqls) == 0 {
ctx.Sqls = m.SqlNodes
}
ctx.DefaultNamespace = m.NameSpace
for _, a := range m.QueryNodes {
data, err := a.GetStmt(ctx)
if err == nil {
Expand Down
44 changes: 44 additions & 0 deletions ast/mappers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ast

import (
"errors"
"fmt"
)

type Mappers struct {
mappers []*Mapper
}

func NewMappers() *Mappers {
return &Mappers{}
}

func (s *Mappers) AddMapper(ms ...*Mapper) error {
for _, m := range ms {
if m == nil {
return errors.New("can not add null mapper to mappers")
}
s.mappers = append(s.mappers, m)
}
return nil
}

func (s *Mappers) GetStmts(skipErrorQuery bool) ([]string, error) {
ctx := NewContext()
stmts := []string{}
for _, m := range s.mappers {
for id, node := range m.SqlNodes {
ctx.Sqls[fmt.Sprintf("%v.%v", m.NameSpace, id)] = node
}
}

for _, m := range s.mappers {
ctx.DefaultNamespace = m.NameSpace
stmt, err := m.GetStmts(ctx, skipErrorQuery)
if err != nil {
return nil, fmt.Errorf("get sqls from mapper failed, namespace: %v, err: %v", m.NameSpace, err)
}
stmts = append(stmts, stmt...)
}
return stmts, nil
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ go 1.14
require (
github.com/pingcap/parser v3.0.12+incompatible
github.com/pingcap/tidb v0.0.0-20200312110807-8c4696b3f340 // v3.0.12
github.com/stretchr/testify v1.3.0
)
42 changes: 42 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package parser

import (
"encoding/xml"
"errors"
"fmt"
"io"
"strings"
Expand All @@ -27,6 +28,47 @@ func ParseXML(data string) (string, error) {
return stmt, nil
}

// ParseXMLs is a parser for parse all query in several XML files to []string one by one;
// you can set `skipErrorQuery` true to ignore invalid query.
func ParseXMLs(data []string, skipErrorQuery bool) ([]string, error) {
ms := ast.NewMappers()
for i := range data {
r := strings.NewReader(data[i])
d := xml.NewDecoder(r)
n, err := parse(d)
if err != nil {
if skipErrorQuery {
continue
} else {
return nil, err
}
}

if n == nil {
continue
}

m, ok := n.(*ast.Mapper)
if !ok {
if skipErrorQuery {
continue
} else {
return nil, errors.New("the mapper is not found")
}
}
err = ms.AddMapper(m)
if err != nil && !skipErrorQuery {
return nil, fmt.Errorf("add mapper failed: %v", err)
}
}
stmts, err := ms.GetStmts(skipErrorQuery)
if err != nil {
return nil, err
}

return stmts, nil
}

// ParseXMLQuery is a parser for parse all query in XML to []string one by one;
// you can set `skipErrorQuery` true to ignore invalid query.
func ParseXMLQuery(data string, skipErrorQuery bool) ([]string, error) {
Expand Down
61 changes: 61 additions & 0 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package parser

import (
"testing"

"github.com/stretchr/testify/assert"
)

func testParser(t *testing.T, xmlData, expect string) {
Expand Down Expand Up @@ -1046,3 +1048,62 @@ func TestOtherwise_issue1193(t *testing.T) {
`, "SELECT * FROM `fruits` WHERE `name`=? AND `price`=? AND `category`=?;",
)
}

func TestParseXMLs(t *testing.T) {
xmlCommonData := `
<?xml version="1.0" encoding="UTF-8"?><!--Converted at: Mon Jun 07 09:48:24 CST 2021-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test.common">
<sql id="prefix">
SELECT * FROM (
</sql>
<sql id="suffix">
WHERE a=1 )
</sql>
<select id="sql1" parameterType="customer" resultMap="custResultMap">
<include refid="prefix"/>
SELECT a,b FROM tb1
<include refid="suffix"/>
</select>
</mapper>
`
xmlData := `
<?xml version="1.0" encoding="UTF-8"?><!--Converted at: Tue May 10 15:50:21 CST 2022-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="employee">
<select id="queryEmpHireSepList" parameterType="employee" resultType="employeeResult">
<include refid="test.common.prefix"/>
SELECT a,b FROM tb1
<include refid="test.common.suffix"/>
</select>
</mapper>
`

sqls, err := ParseXMLs([]string{xmlCommonData, xmlData}, false)
if err != nil {
if !assert.NoError(t, err) {
t.Fatal(err)
}
}
assert.Equal(t, 2, len(sqls))
assert.Equal(t, `
SELECT * FROM (
SELECT a,b FROM tb1
WHERE a=1 )
`, sqls[0])

assert.Equal(t, `
SELECT * FROM (
SELECT a,b FROM tb1
WHERE a=1 )
`, sqls[1])

}
15 changes: 15 additions & 0 deletions vendor/github.com/davecgh/go-spew/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

145 changes: 145 additions & 0 deletions vendor/github.com/davecgh/go-spew/spew/bypass.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ec9bc09

Please sign in to comment.