Skip to content

Commit e82e2da

Browse files
authored
fix(analyzer): weekly parsed update query must have all the columns as targets (#52)
1 parent 67f5ebd commit e82e2da

4 files changed

Lines changed: 46 additions & 6 deletions

File tree

analyzer/analyzer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (a *analyzer) analyzeQueries(queries []string) (domains.CachePlan, error) {
4848
query = normalizer.NormalizeQuery(query)
4949
parsed, err := sql_parser.ParseSQL(query)
5050
if err != nil {
51-
weekParsed, weekErr := sql_parser.ParseSQLWeekly(query)
51+
weekParsed, weekErr := sql_parser.ParseSQLWeekly(query, a.schemas)
5252
if weekErr != nil {
5353
planErr.errors = append(planErr.errors, fmt.Errorf("failed to parse query:\nmain -> %s\nweek -> %s", err, weekErr))
5454
continue

analyzer/analyzer_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,15 @@ func TestAnalyzeQueries(t *testing.T) {
264264
Type: domains.CachePlanQueryType_UPDATE,
265265
},
266266
Update: &domains.CachePlanUpdateQuery{
267-
Table: "users",
267+
Table: "users",
268+
Targets: []domains.CachePlanUpdateTarget{
269+
{Column: "account_name", Placeholder: domains.CachePlanPlaceholder{Index: 0}},
270+
{Column: "authority", Placeholder: domains.CachePlanPlaceholder{Index: 1}},
271+
{Column: "created_at", Placeholder: domains.CachePlanPlaceholder{Index: 2}},
272+
{Column: "del_flg", Placeholder: domains.CachePlanPlaceholder{Index: 3}},
273+
{Column: "id", Placeholder: domains.CachePlanPlaceholder{Index: 4}},
274+
{Column: "passhash", Placeholder: domains.CachePlanPlaceholder{Index: 5}},
275+
},
268276
Conditions: []domains.CachePlanCondition{},
269277
},
270278
},

sql_parser/week_parser.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,42 @@ package sql_parser
33
import (
44
"fmt"
55
"regexp"
6+
"slices"
7+
8+
"github.com/traP-jp/isuc/domains"
69
)
710

811
var selectStmtRegex = regexp.MustCompile("^SELECT\\s+`?(?P<columns>.+)`?\\s+FROM\\s+`?(?P<table>\\w+)`?")
912
var updateStmtRegex = regexp.MustCompile("^UPDATE\\s+`?(?P<table>\\w+)`?")
1013
var deleteStmtRegex = regexp.MustCompile("^DELETE\\s+FROM\\s+`?(?P<table>\\w+)`?")
1114
var insertStmtRegex = regexp.MustCompile("^INSERT\\s+INTO\\s+`?(?P<table>\\w+)`?")
1215

13-
func ParseSQLWeekly(query string) (SQLNode, error) {
16+
func ParseSQLWeekly(query string, schemas []domains.TableSchema) (SQLNode, error) {
1417
if match := matchRegex(selectStmtRegex, query); match != nil {
1518
return SelectStmtNode{Table: TableNode{Name: match["table"]}}, nil
1619
}
1720
if match := matchRegex(updateStmtRegex, query); match != nil {
18-
return UpdateStmtNode{Table: TableNode{Name: match["table"]}}, nil
21+
schema := domains.TableSchema{}
22+
for _, s := range schemas {
23+
if s.TableName == match["table"] {
24+
schema = s
25+
break
26+
}
27+
}
28+
if schema.TableName == "" {
29+
return nil, fmt.Errorf("table not found: %s", match["table"])
30+
}
31+
sets := make([]UpdateSetNode, 0, len(schema.Columns))
32+
// ensure the order of columns
33+
keys := make([]string, 0, len(schema.Columns))
34+
for key := range schema.Columns {
35+
keys = append(keys, key)
36+
}
37+
slices.Sort(keys)
38+
for _, column := range keys {
39+
sets = append(sets, UpdateSetNode{Column: ColumnNode{Name: schema.Columns[column].ColumnName}, Value: PlaceholderNode{}})
40+
}
41+
return UpdateStmtNode{Table: TableNode{Name: match["table"]}, Sets: UpdateSetsNode{Sets: sets}}, nil
1942
}
2043
if match := matchRegex(deleteStmtRegex, query); match != nil {
2144
return DeleteStmtNode{Table: TableNode{Name: match["table"]}}, nil

sql_parser/week_parser_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"testing"
55

66
"github.com/stretchr/testify/assert"
7+
"github.com/traP-jp/isuc/domains"
78
)
89

910
func TestParseSQLWeekly(t *testing.T) {
@@ -21,7 +22,10 @@ func TestParseSQLWeekly(t *testing.T) {
2122
},
2223
{
2324
query: "UPDATE users SET del_flg = 1 WHERE id % 50 = 0",
24-
node: UpdateStmtNode{Table: TableNode{Name: "users"}},
25+
node: UpdateStmtNode{Table: TableNode{Name: "users"}, Sets: UpdateSetsNode{Sets: []UpdateSetNode{
26+
{Column: ColumnNode{Name: "del_flg"}, Value: PlaceholderNode{}},
27+
{Column: ColumnNode{Name: "id"}, Value: PlaceholderNode{}},
28+
}}},
2529
},
2630
{
2731
query: "DELETE FROM livecomments WHERE id = ? AND livestream_id = ? AND (SELECT COUNT(*) FROM (SELECT ? AS text) AS texts INNER JOIN (SELECT CONCAT('%', ?, '%') AS pattern) AS patterns ON texts.text LIKE patterns.pattern) >= 1;",
@@ -30,7 +34,12 @@ func TestParseSQLWeekly(t *testing.T) {
3034
}
3135

3236
for _, test := range tests {
33-
node, err := ParseSQLWeekly(test.query)
37+
node, err := ParseSQLWeekly(test.query, []domains.TableSchema{
38+
{TableName: "users", Columns: map[string]domains.TableSchemaColumn{
39+
"id": {ColumnName: "id"},
40+
"del_flg": {ColumnName: "del_flg"},
41+
}},
42+
})
3443
assert.NoError(t, err)
3544
assert.Equal(t, test.node, node)
3645
}

0 commit comments

Comments
 (0)