Skip to content

Commit

Permalink
Merge pull request #649 from upper/refactor-memory-and-speed-optimiza…
Browse files Browse the repository at this point in the history
…tions

optimize `prepareQueryForDisplay`
  • Loading branch information
xiam committed Mar 8, 2022
2 parents 78486f2 + 471ba7e commit f79575d
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 18 deletions.
55 changes: 37 additions & 18 deletions internal/sqlbuilder/builder.go
Expand Up @@ -29,7 +29,6 @@ import (
"fmt"
"log"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -72,10 +71,6 @@ type fieldValue struct {
values []interface{}
}

var (
reInvisibleChars = regexp.MustCompile(`[\s\r\n\t]+`)
)

var (
sqlPlaceholder = exql.RawValue(`?`)
)
Expand Down Expand Up @@ -347,11 +342,10 @@ func Map(item interface{}, options *MapOptions) ([]string, []interface{}, error)
}

func columnFragments(columns []interface{}) ([]exql.Fragment, []interface{}, error) {
l := len(columns)
f := make([]exql.Fragment, l)
f := make([]exql.Fragment, len(columns))
args := []interface{}{}

for i := 0; i < l; i++ {
for i := range columns {
switch v := columns[i].(type) {
case compilable:
c, err := v.Compile()
Expand Down Expand Up @@ -393,19 +387,44 @@ func columnFragments(columns []interface{}) ([]exql.Fragment, []interface{}, err
return f, args, nil
}

func prepareQueryForDisplay(in string) (out string) {
j := 1
for i := range in {
func prepareQueryForDisplay(in string) string {
out := make([]byte, 0, len(in))

offset := 0
whitespace := true
placeholders := 1

for i := 0; i < len(in); i++ {
if in[i] == ' ' || in[i] == '\r' || in[i] == '\n' || in[i] == '\t' {
if whitespace {
offset = i
} else {
whitespace = true
out = append(out, in[offset:i]...)
offset = i
}
continue
}
if whitespace {
whitespace = false
if len(out) > 0 {
out = append(out, ' ')
}
offset = i
}
if in[i] == '?' {
out = out + "$" + strconv.Itoa(j)
j++
} else {
out = out + string(in[i])
out = append(out, in[offset:i]...)
offset = i + 1

out = append(out, '$')
out = append(out, strconv.Itoa(placeholders)...)
placeholders++
}
}

out = reInvisibleChars.ReplaceAllString(out, ` `)
return strings.TrimSpace(out)
if !whitespace {
out = append(out, in[offset:len(in)]...)
}
return string(out)
}

func (iter *iterator) NextScan(dst ...interface{}) error {
Expand Down
5 changes: 5 additions & 0 deletions internal/sqlbuilder/builder_test.go
Expand Up @@ -2,13 +2,18 @@ package sqlbuilder

import (
"fmt"
"regexp"
"strings"
"testing"

"github.com/stretchr/testify/assert"
db "github.com/upper/db/v4"
)

var (
reInvisibleChars = regexp.MustCompile(`[\s\r\n\t]+`)
)

func TestSelect(t *testing.T) {

b := &sqlBuilder{t: newTemplateWithUtils(&testTemplate)}
Expand Down
63 changes: 63 additions & 0 deletions internal/sqlbuilder/placeholder_test.go
Expand Up @@ -7,6 +7,69 @@ import (
db "github.com/upper/db/v4"
)

func TestPrepareForDisplay(t *testing.T) {
samples := []struct {
In string
Out string
}{
{
In: "12345",
Out: "12345",
},
{
In: "\r\n\t12345",
Out: "12345",
},
{
In: "12345\r\n\t",
Out: "12345",
},
{
In: "\r\n\t1\r2\n3\t4\r5\r\n\t",
Out: "1 2 3 4 5",
},
{
In: "\r\n \t 1\r 2\n 3\t 4\r 5\r \n\t",
Out: "1 2 3 4 5",
},
{
In: "\r\n \t 11\r 22\n 33\t 44 \r 55",
Out: "11 22 33 44 55",
},
{
In: "11\r 22\n 33\t 44 \r 55",
Out: "11 22 33 44 55",
},
{
In: "1 2 3 4 5",
Out: "1 2 3 4 5",
},
{
In: "?",
Out: "$1",
},
{
In: "? ?",
Out: "$1 $2",
},
{
In: "? ? ?",
Out: "$1 $2 $3",
},
{
In: " ? ? ? ",
Out: "$1 $2 $3",
},
{
In: "???",
Out: "$1$2$3",
},
}
for _, sample := range samples {
assert.Equal(t, sample.Out, prepareQueryForDisplay(sample.In))
}
}

func TestPlaceholderSimple(t *testing.T) {
{
ret, _ := Preprocess("?", []interface{}{1})
Expand Down

0 comments on commit f79575d

Please sign in to comment.