Skip to content

Commit

Permalink
normalize対応
Browse files Browse the repository at this point in the history
  • Loading branch information
mazrean committed Oct 8, 2023
1 parent f442dd2 commit ab541bf
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 4 deletions.
50 changes: 48 additions & 2 deletions db/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package isudb

import (
"database/sql"
"regexp"
"sync"

"github.com/go-sql-driver/mysql"
)
Expand All @@ -23,7 +25,51 @@ func (msb mysqlSegmentBuilder) parseDSN(dsn string) *measureSegment {
}

return &measureSegment{
driver: msb.driver(),
addr: cfg.Addr,
driver: msb.driver(),
addr: cfg.Addr,
normalizer: msb.normalizer,
}
}

var (
mysqlReList = []struct {
re *regexp.Regexp
to string
}{{
re: regexp.MustCompile(`(\?\s*,\s*)+`),
to: "..., ",
}, {
re: regexp.MustCompile(`(\(..., \?\)\s*,\s*)+`),
to: "..., ",
}}
mysqlNormalizeCacheLocker = &sync.RWMutex{}
mysqlNormalizeCache = make(map[string]string, 50)
)

func (mysqlSegmentBuilder) normalizer(query string) string {
var (
normalizedQuery string
ok bool
)
func() {
mysqlNormalizeCacheLocker.RLock()
defer mysqlNormalizeCacheLocker.RUnlock()
normalizedQuery, ok = mysqlNormalizeCache[query]
}()
if ok {
return normalizedQuery
}

normalizedQuery = query
for _, re := range mysqlReList {
normalizedQuery = re.re.ReplaceAllString(normalizedQuery, re.to)
}

func() {
mysqlNormalizeCacheLocker.Lock()
defer mysqlNormalizeCacheLocker.Unlock()
mysqlNormalizeCache[query] = normalizedQuery
}()

return normalizedQuery
}
31 changes: 31 additions & 0 deletions db/mysql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package isudb

import (
"fmt"
"strings"
"testing"
)

func BenchmarkMySQLNormalizer(b *testing.B) {
msb := mysqlSegmentBuilder{}

queryPart := fmt.Sprintf("(%s?)", strings.Repeat("?, ", 5))
query := fmt.Sprintf("INSERT INTO users (name, email, password, salt, created_at, updated_at) VALUES %s", strings.Repeat(queryPart+", ", 999)+queryPart)

for i := 0; i < b.N; i++ {
msb.normalizer(query)
}
}

func TestMySQLNormalizer(t *testing.T) {
msb := mysqlSegmentBuilder{}

queryPart := fmt.Sprintf("(%s?)", strings.Repeat("?, ", 5))
query := fmt.Sprintf("INSERT INTO users (name, email, password, salt, created_at, updated_at) VALUES %s", strings.Repeat(queryPart+", ", 999)+queryPart)

normalizedQuery := msb.normalizer(query)

if normalizedQuery != "INSERT INTO users (name, email, password, salt, created_at, updated_at) VALUES ..., (..., ?)" {
t.Errorf("unexpected query: %s", normalizedQuery)
}
}
50 changes: 48 additions & 2 deletions db/sqlite3.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package isudb

import (
"database/sql"
"regexp"
"sync"

"github.com/mattn/go-sqlite3"
)
Expand All @@ -18,7 +20,51 @@ func (sqlite3SegmentBuilder) driver() string {

func (ssb sqlite3SegmentBuilder) parseDSN(dsn string) *measureSegment {
return &measureSegment{
driver: ssb.driver(),
addr: dsn,
driver: ssb.driver(),
addr: dsn,
normalizer: ssb.normalizer,
}
}

var (
sqliteReList = []struct {
re *regexp.Regexp
to string
}{{
re: regexp.MustCompile(`((?:\?(\d*)|[@:$][0-9A-Fa-f]+)\s*,\s*)+`),
to: "..., ",
}, {
re: regexp.MustCompile(`(\(\.\.\., ((\?[0-9]*)|[@:$][0-9A-Fa-f]+)\)\s*,\s*)+`),
to: "..., ",
}}
sqlite3NormalizeCacheLocker = &sync.RWMutex{}
sqlite3NormalizeCache = make(map[string]string, 50)
)

func (sqlite3SegmentBuilder) normalizer(query string) string {
var (
normalizedQuery string
ok bool
)
func() {
sqlite3NormalizeCacheLocker.RLock()
defer sqlite3NormalizeCacheLocker.RUnlock()
normalizedQuery, ok = sqlite3NormalizeCache[query]
}()
if ok {
return normalizedQuery
}

normalizedQuery = query
for _, re := range sqliteReList {
normalizedQuery = re.re.ReplaceAllString(normalizedQuery, re.to)
}

func() {
sqlite3NormalizeCacheLocker.Lock()
defer sqlite3NormalizeCacheLocker.Unlock()
sqlite3NormalizeCache[query] = normalizedQuery
}()

return normalizedQuery
}
46 changes: 46 additions & 0 deletions db/sqlite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package isudb

import (
"fmt"
"strings"
"testing"
)

func BenchmarkSQLite3Normalizer(b *testing.B) {
ssb := sqlite3SegmentBuilder{}

queryPart := fmt.Sprintf("(%s?)", strings.Repeat("?, ", 5))
query := fmt.Sprintf("INSERT INTO users (name, email, password, salt, created_at, updated_at) VALUES %s", strings.Repeat(queryPart+", ", 999)+queryPart)

for i := 0; i < b.N; i++ {
ssb.normalizer(query)
}
}

func TestSQLite3Normalizer(t *testing.T) {
ssb := sqlite3SegmentBuilder{}

tests := []string{
"?",
"?1234",
":a1",
"@a1",
"$a1",
}

for _, test := range tests {
test := test
t.Run(test, func(t *testing.T) {
t.Parallel()

queryPart := fmt.Sprintf("(%s%s)", strings.Repeat(fmt.Sprintf("%s, ", test), 5), test)
query := fmt.Sprintf("INSERT INTO users (name, email, password, salt, created_at, updated_at) VALUES %s", strings.Repeat(queryPart+", ", 999)+queryPart)

normalizedQuery := ssb.normalizer(query)

if normalizedQuery != fmt.Sprintf("INSERT INTO users (name, email, password, salt, created_at, updated_at) VALUES ..., (..., %s)", test) {
t.Errorf("unexpected query: %s", normalizedQuery)
}
})
}
}
3 changes: 3 additions & 0 deletions tools.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build tools
// +build tools

package isutools

import (
Expand Down

0 comments on commit ab541bf

Please sign in to comment.