compile named query: drop of loop over runes 30% performance improvement

This commit is contained in:
Michał Matczuk
2017-07-26 09:10:35 +02:00
parent b05f30bb93
commit 871a3693ad

View File

@@ -6,18 +6,11 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
"unicode"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/jmoiron/sqlx/reflectx" "github.com/jmoiron/sqlx/reflectx"
) )
// Allow digits and letters in bind params; additionally runes are
// checked against underscores, meaning that bind params can have be
// alphanumeric with underscores. Mind the difference between unicode
// digits and numbers, where '5' is a digit but '五' is not.
var allowedBindRunes = []*unicode.RangeTable{unicode.Letter, unicode.Digit}
// CompileNamedQuery compiles a named query into an unbound query using the // CompileNamedQuery compiles a named query into an unbound query using the
// '?' bindvar and a list of names. // '?' bindvar and a list of names.
func CompileNamedQuery(qs []byte) (stmt string, names []string, err error) { func CompileNamedQuery(qs []byte) (stmt string, names []string, err error) {
@@ -48,7 +41,7 @@ func CompileNamedQuery(qs []byte) (stmt string, names []string, err error) {
inName = true inName = true
name = []byte{} name = []byte{}
// if we're in a name, and this is an allowed character, continue // if we're in a name, and this is an allowed character, continue
} else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last { } else if inName && (allowedBindRune(b) || b == '_' || b == '.') && i != last {
// append the byte to the name if we are in a name and not on the last byte // append the byte to the name if we are in a name and not on the last byte
name = append(name, b) name = append(name, b)
// if we're in a name and it's not an allowed character, the name is done // if we're in a name and it's not an allowed character, the name is done
@@ -56,7 +49,7 @@ func CompileNamedQuery(qs []byte) (stmt string, names []string, err error) {
inName = false inName = false
// if this is the final byte of the string and it is part of the name, then // if this is the final byte of the string and it is part of the name, then
// make sure to add it to the name // make sure to add it to the name
if i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) { if i == last && allowedBindRune(b) {
name = append(name, b) name = append(name, b)
} }
// add the string representation to the names list // add the string representation to the names list
@@ -66,7 +59,7 @@ func CompileNamedQuery(qs []byte) (stmt string, names []string, err error) {
// add this byte to string unless it was not part of the name // add this byte to string unless it was not part of the name
if i != last { if i != last {
rebound = append(rebound, b) rebound = append(rebound, b)
} else if !unicode.IsOneOf(allowedBindRunes, rune(b)) { } else if !allowedBindRune(b) {
rebound = append(rebound, b) rebound = append(rebound, b)
} }
} else { } else {
@@ -78,6 +71,10 @@ func CompileNamedQuery(qs []byte) (stmt string, names []string, err error) {
return string(rebound), names, err return string(rebound), names, err
} }
func allowedBindRune(b byte) bool {
return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')
}
// Queryx is a wrapper around gocql.Query which adds struct binding capabilities. // Queryx is a wrapper around gocql.Query which adds struct binding capabilities.
type Queryx struct { type Queryx struct {
*gocql.Query *gocql.Query