Skip to content

Commit

Permalink
🧀 🍤 🌶️ fix(analyzer): weekly parsed update query must have all the co…
Browse files Browse the repository at this point in the history
…lumns as targets
  • Loading branch information
cp-20 committed Feb 1, 2025
1 parent 67f5ebd commit 52f2d4f
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 6 deletions.
2 changes: 1 addition & 1 deletion analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (a *analyzer) analyzeQueries(queries []string) (domains.CachePlan, error) {
query = normalizer.NormalizeQuery(query)
parsed, err := sql_parser.ParseSQL(query)
if err != nil {
weekParsed, weekErr := sql_parser.ParseSQLWeekly(query)
weekParsed, weekErr := sql_parser.ParseSQLWeekly(query, a.schemas)
if weekErr != nil {
planErr.errors = append(planErr.errors, fmt.Errorf("failed to parse query:\nmain -> %s\nweek -> %s", err, weekErr))
continue
Expand Down
10 changes: 9 additions & 1 deletion analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,15 @@ func TestAnalyzeQueries(t *testing.T) {
Type: domains.CachePlanQueryType_UPDATE,
},
Update: &domains.CachePlanUpdateQuery{
Table: "users",
Table: "users",
Targets: []domains.CachePlanUpdateTarget{
{Column: "account_name", Placeholder: domains.CachePlanPlaceholder{Index: 0}},
{Column: "authority", Placeholder: domains.CachePlanPlaceholder{Index: 1}},
{Column: "created_at", Placeholder: domains.CachePlanPlaceholder{Index: 2}},
{Column: "del_flg", Placeholder: domains.CachePlanPlaceholder{Index: 3}},
{Column: "id", Placeholder: domains.CachePlanPlaceholder{Index: 4}},
{Column: "passhash", Placeholder: domains.CachePlanPlaceholder{Index: 5}},
},
Conditions: []domains.CachePlanCondition{},
},
},
Expand Down
27 changes: 25 additions & 2 deletions sql_parser/week_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,42 @@ package sql_parser
import (
"fmt"
"regexp"
"slices"

"github.com/traP-jp/isuc/domains"
)

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

func ParseSQLWeekly(query string) (SQLNode, error) {
func ParseSQLWeekly(query string, schemas []domains.TableSchema) (SQLNode, error) {
if match := matchRegex(selectStmtRegex, query); match != nil {
return SelectStmtNode{Table: TableNode{Name: match["table"]}}, nil
}
if match := matchRegex(updateStmtRegex, query); match != nil {
return UpdateStmtNode{Table: TableNode{Name: match["table"]}}, nil
schema := domains.TableSchema{}
for _, s := range schemas {
if s.TableName == match["table"] {
schema = s
break
}
}
if schema.TableName == "" {
return nil, fmt.Errorf("table not found: %s", match["table"])
}
sets := make([]UpdateSetNode, 0, len(schema.Columns))
// ensure the order of columns
keys := make([]string, 0, len(schema.Columns))
for key := range schema.Columns {
keys = append(keys, key)
}
slices.Sort(keys)
for _, column := range keys {
sets = append(sets, UpdateSetNode{Column: ColumnNode{Name: schema.Columns[column].ColumnName}, Value: PlaceholderNode{}})
}
return UpdateStmtNode{Table: TableNode{Name: match["table"]}, Sets: UpdateSetsNode{Sets: sets}}, nil
}
if match := matchRegex(deleteStmtRegex, query); match != nil {
return DeleteStmtNode{Table: TableNode{Name: match["table"]}}, nil
Expand Down
13 changes: 11 additions & 2 deletions sql_parser/week_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/traP-jp/isuc/domains"
)

func TestParseSQLWeekly(t *testing.T) {
Expand All @@ -21,7 +22,10 @@ func TestParseSQLWeekly(t *testing.T) {
},
{
query: "UPDATE users SET del_flg = 1 WHERE id % 50 = 0",
node: UpdateStmtNode{Table: TableNode{Name: "users"}},
node: UpdateStmtNode{Table: TableNode{Name: "users"}, Sets: UpdateSetsNode{Sets: []UpdateSetNode{
{Column: ColumnNode{Name: "del_flg"}, Value: PlaceholderNode{}},
{Column: ColumnNode{Name: "id"}, Value: PlaceholderNode{}},
}}},
},
{
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;",
Expand All @@ -30,7 +34,12 @@ func TestParseSQLWeekly(t *testing.T) {
}

for _, test := range tests {
node, err := ParseSQLWeekly(test.query)
node, err := ParseSQLWeekly(test.query, []domains.TableSchema{
{TableName: "users", Columns: map[string]domains.TableSchemaColumn{
"id": {ColumnName: "id"},
"del_flg": {ColumnName: "del_flg"},
}},
})
assert.NoError(t, err)
assert.Equal(t, test.node, node)
}
Expand Down

0 comments on commit 52f2d4f

Please sign in to comment.