Browse Source

refactor(*): remove sprintf and split

Avoid doing calculation in runtime

Signed-off-by: Jiyong Huang <huangjy@emqx.io>
Jiyong Huang 3 năm trước cách đây
mục cha
commit
5a1bfc5d55

+ 1 - 1
internal/service/schema.go

@@ -315,7 +315,7 @@ func (d *wrappedProtoDescriptor) unfoldMap(ft *desc.MessageDescriptor, i interfa
 	result := make([]interface{}, len(fields))
 	if m, ok := xsql.ToMessage(i); ok {
 		for _, field := range fields {
-			v, ok := m.Value(field.GetName())
+			v, ok := m.Value(field.GetName(), "")
 			if !ok {
 				return nil, fmt.Errorf("field %s not found", field.GetName())
 			}

+ 2 - 2
internal/topo/operator/field_processor.go

@@ -52,7 +52,7 @@ func (p *defaultFieldProcessor) processField(tuple *xsql.Tuple, _ *xsql.Function
 				if p.isBinary {
 					result = tuple.Message
 				} else {
-					if m, ok := tuple.Message.Value(sf); ok {
+					if m, ok := tuple.Message.Value(sf, ""); ok {
 						result[sf] = m
 					}
 				}
@@ -68,7 +68,7 @@ func (p *defaultFieldProcessor) processField(tuple *xsql.Tuple, _ *xsql.Function
 }
 
 func (p *defaultFieldProcessor) addRecField(ft ast.FieldType, r map[string]interface{}, j xsql.Message, n string) error {
-	if t, ok := j.Value(n); ok {
+	if t, ok := j.Value(n, ""); ok {
 		v := reflect.ValueOf(t)
 		jtype := v.Kind()
 		switch st := ft.(type) {

+ 1 - 1
internal/topo/operator/preprocessor.go

@@ -73,7 +73,7 @@ func (p *Preprocessor) Apply(ctx api.StreamContext, data interface{}, _ *xsql.Fu
 	if !p.allMeta && p.metaFields != nil && len(p.metaFields) > 0 {
 		newMeta := make(xsql.Metadata)
 		for _, f := range p.metaFields {
-			if m, ok := tuple.Metadata.Value(f); ok {
+			if m, ok := tuple.Metadata.Value(f, ""); ok {
 				newMeta[f] = m
 			}
 		}

+ 6 - 3
internal/xsql/ast_test.go

@@ -25,6 +25,7 @@ import (
 func Test_MessageValTest(t *testing.T) {
 	var tests = []struct {
 		key     string
+		table   string
 		message Message
 		exptV   interface{}
 		exptOk  bool
@@ -60,7 +61,8 @@ func Test_MessageValTest(t *testing.T) {
 		},
 
 		{
-			key: "key1" + ast.COLUMN_SEPARATOR + "subkey",
+			key:   "subkey",
+			table: "key1",
 			message: Message{
 				"Key1":   "val1",
 				"subkey": "subval",
@@ -80,7 +82,8 @@ func Test_MessageValTest(t *testing.T) {
 		},
 
 		{
-			key: "parent" + ast.COLUMN_SEPARATOR + "child",
+			key:   "child",
+			table: "parent",
 			message: Message{
 				"key1":         "val1",
 				"child":        "child_val",
@@ -116,7 +119,7 @@ func Test_MessageValTest(t *testing.T) {
 	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
 	for i, tt := range tests {
 		//fmt.Printf("Parsing SQL %q.\n", tt.s)
-		v, ok := tt.message.Value(tt.key)
+		v, ok := tt.message.Value(tt.key, tt.table)
 		if tt.exptOk != ok {
 			t.Errorf("%d. error mismatch:\n  exp=%t\n  got=%t\n\n", i, tt.exptOk, ok)
 		} else if tt.exptOk && !reflect.DeepEqual(tt.exptV, v) {

+ 32 - 51
internal/xsql/collections.go

@@ -48,22 +48,13 @@ func ToMessage(input interface{}) (Message, bool) {
 }
 
 // Value returns the value for a key in the Message.
-func (m Message) Value(key string) (interface{}, bool) {
-	var colkey string
-	if keys := strings.Split(key, ast.COLUMN_SEPARATOR); len(keys) == 1 {
-		colkey = key
-	} else if len(keys) == 2 {
-		colkey = keys[1]
-	} else {
-		conf.Log.Println("Invalid key: " + key + ", expect source.field or field.")
-		return nil, false
-	}
-	if v, ok := m[colkey]; ok {
+func (m Message) Value(key, table string) (interface{}, bool) {
+	if v, ok := m[key]; ok {
 		return v, ok
 	} else {
 		//Only when with 'SELECT * FROM ...'  and 'schemaless', the key in map is not convert to lower case.
 		//So all of keys in map should be convert to lowercase and then compare them.
-		return m.getIgnoreCase(colkey)
+		return m.getIgnoreCase(key)
 	}
 }
 
@@ -78,11 +69,11 @@ func (m Message) getIgnoreCase(key interface{}) (interface{}, bool) {
 	return nil, false
 }
 
-func (m Message) Meta(key string) (interface{}, bool) {
+func (m Message) Meta(key, table string) (interface{}, bool) {
 	if key == "*" {
 		return map[string]interface{}(m), true
 	}
-	return m.Value(key)
+	return m.Value(key, table)
 }
 
 func (m Message) AppendAlias(k string, v interface{}) bool {
@@ -97,17 +88,17 @@ type Event interface {
 
 type Metadata Message
 
-func (m Metadata) Value(key string) (interface{}, bool) {
+func (m Metadata) Value(key, table string) (interface{}, bool) {
 	msg := Message(m)
-	return msg.Value(key)
+	return msg.Value(key, table)
 }
 
-func (m Metadata) Meta(key string) (interface{}, bool) {
+func (m Metadata) Meta(key, table string) (interface{}, bool) {
 	if key == "*" {
 		return map[string]interface{}(m), true
 	}
 	msg := Message(m)
-	return msg.Meta(key)
+	return msg.Meta(key, table)
 }
 
 type Alias struct {
@@ -126,7 +117,7 @@ func (a *Alias) AliasValue(key string) (interface{}, bool) {
 	if a.AliasMap == nil {
 		return nil, false
 	}
-	return a.AliasMap.Value(key)
+	return a.AliasMap.Value(key, "")
 }
 
 type Tuple struct {
@@ -137,19 +128,19 @@ type Tuple struct {
 	Alias
 }
 
-func (t *Tuple) Value(key string) (interface{}, bool) {
+func (t *Tuple) Value(key, table string) (interface{}, bool) {
 	r, ok := t.AliasValue(key)
 	if ok {
 		return r, ok
 	}
-	return t.Message.Value(key)
+	return t.Message.Value(key, table)
 }
 
-func (t *Tuple) Meta(key string) (interface{}, bool) {
+func (t *Tuple) Meta(key, table string) (interface{}, bool) {
 	if key == "*" {
 		return map[string]interface{}(t.Metadata), true
 	}
-	return t.Metadata.Value(key)
+	return t.Metadata.Value(key, table)
 }
 
 func (t *Tuple) All(string) (interface{}, bool) {
@@ -203,11 +194,11 @@ type WindowRangeValuer struct {
 	*WindowRange
 }
 
-func (r *WindowRangeValuer) Value(_ string) (interface{}, bool) {
+func (r *WindowRangeValuer) Value(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 
-func (r *WindowRangeValuer) Meta(_ string) (interface{}, bool) {
+func (r *WindowRangeValuer) Meta(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 
@@ -321,26 +312,20 @@ func (jt *JoinTuple) AddTuples(tuples []Tuple) {
 	}
 }
 
-func getTupleValue(tuple Tuple, t string, key string) (interface{}, bool) {
-	switch t {
-	case "value":
-		return tuple.Value(key)
-	case "meta":
-		return tuple.Meta(key)
-	default:
-		conf.Log.Errorf("cannot get tuple for type %s", t)
-		return nil, false
+func getTupleValue(tuple Tuple, key string, isVal bool) (interface{}, bool) {
+	if isVal {
+		return tuple.Value(key, "")
+	} else {
+		return tuple.Meta(key, "")
 	}
 }
 
-func (jt *JoinTuple) doGetValue(t string, key string) (interface{}, bool) {
-	keys := strings.Split(key, ast.COLUMN_SEPARATOR)
+func (jt *JoinTuple) doGetValue(key, table string, isVal bool) (interface{}, bool) {
 	tuples := jt.Tuples
-	switch len(keys) {
-	case 1:
+	if table == "" {
 		if len(tuples) > 1 {
 			for _, tuple := range tuples { //TODO support key without modifier?
-				v, ok := getTupleValue(tuple, t, key)
+				v, ok := getTupleValue(tuple, key, isVal)
 				if ok {
 					return v, ok
 				}
@@ -348,33 +333,29 @@ func (jt *JoinTuple) doGetValue(t string, key string) (interface{}, bool) {
 			conf.Log.Debugf("Wrong key: %s not found", key)
 			return nil, false
 		} else {
-			return getTupleValue(tuples[0], t, key)
+			return getTupleValue(tuples[0], key, isVal)
 		}
-	case 2:
-		emitter, key := keys[0], keys[1]
+	} else {
 		//TODO should use hash here
 		for _, tuple := range tuples {
-			if tuple.Emitter == emitter {
-				return getTupleValue(tuple, t, key)
+			if tuple.Emitter == table {
+				return getTupleValue(tuple, key, isVal)
 			}
 		}
 		return nil, false
-	default:
-		conf.Log.Infoln("Wrong key: ", key, ", expect dot in the expression.")
-		return nil, false
 	}
 }
 
-func (jt *JoinTuple) Value(key string) (interface{}, bool) {
+func (jt *JoinTuple) Value(key, table string) (interface{}, bool) {
 	r, ok := jt.AliasValue(key)
 	if ok {
 		return r, ok
 	}
-	return jt.doGetValue("value", key)
+	return jt.doGetValue(key, table, true)
 }
 
-func (jt *JoinTuple) Meta(key string) (interface{}, bool) {
-	return jt.doGetValue("meta", key)
+func (jt *JoinTuple) Meta(key, table string) (interface{}, bool) {
+	return jt.doGetValue(key, table, false)
 }
 
 func (jt *JoinTuple) All(stream string) (interface{}, bool) {

+ 2 - 2
internal/xsql/funcValuer.go

@@ -31,11 +31,11 @@ func NewFunctionValuer(p *funcRuntime) *FunctionValuer {
 	return fv
 }
 
-func (*FunctionValuer) Value(string) (interface{}, bool) {
+func (*FunctionValuer) Value(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 
-func (*FunctionValuer) Meta(string) (interface{}, bool) {
+func (*FunctionValuer) Meta(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 

+ 2 - 2
internal/xsql/funcsAggregate.go

@@ -45,11 +45,11 @@ func (v *AggregateFunctionValuer) GetSingleCallValuer() CallValuer {
 	return v.fv
 }
 
-func (v *AggregateFunctionValuer) Value(string) (interface{}, bool) {
+func (v *AggregateFunctionValuer) Value(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 
-func (v *AggregateFunctionValuer) Meta(string) (interface{}, bool) {
+func (v *AggregateFunctionValuer) Meta(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 

+ 7 - 1
internal/xsql/parser.go

@@ -360,7 +360,13 @@ func (p *Parser) parseSorts() (ast.SortFields, error) {
 
 					p.unscan()
 					if name, err := p.parseFieldNameSections(); err == nil {
-						s.Name = strings.Join(name, ast.COLUMN_SEPARATOR)
+						if len(name) == 2 {
+							s.StreamName = ast.StreamName(name[0])
+							s.Name = name[1]
+						} else {
+							s.Name = name[0]
+						}
+						s.Uname = strings.Join(name, ast.COLUMN_SEPARATOR)
 					} else {
 						return nil, err
 					}

+ 6 - 6
internal/xsql/parser_test.go

@@ -996,7 +996,7 @@ func TestParser_ParseStatement(t *testing.T) {
 						},
 					},
 				},
-				SortFields: []ast.SortField{{Name: "name", Ascending: true}},
+				SortFields: []ast.SortField{{Uname: "name", Name: "name", Ascending: true}},
 			},
 		},
 
@@ -1017,7 +1017,7 @@ func TestParser_ParseStatement(t *testing.T) {
 						},
 					},
 				},
-				SortFields: []ast.SortField{{Name: "s1\007name", Ascending: true}},
+				SortFields: []ast.SortField{{Uname: "s1\007name", Name: "name", StreamName: ast.StreamName("s1"), Ascending: true}},
 			},
 		},
 
@@ -1038,7 +1038,7 @@ func TestParser_ParseStatement(t *testing.T) {
 						},
 					},
 				},
-				SortFields: []ast.SortField{{Name: "name", Ascending: false}},
+				SortFields: []ast.SortField{{Uname: "name", Name: "name", Ascending: false}},
 			},
 		},
 
@@ -1052,7 +1052,7 @@ func TestParser_ParseStatement(t *testing.T) {
 						AName: ""},
 				},
 				Sources:    []ast.Source{&ast.Table{Name: "topic/sensor1"}},
-				SortFields: []ast.SortField{{Name: "name", Ascending: false}},
+				SortFields: []ast.SortField{{Uname: "name", Name: "name", Ascending: false}},
 			},
 		},
 
@@ -1066,7 +1066,7 @@ func TestParser_ParseStatement(t *testing.T) {
 						AName: ""},
 				},
 				Sources:    []ast.Source{&ast.Table{Name: "topic/sensor1"}},
-				SortFields: []ast.SortField{{Name: "name", Ascending: false}, {Name: "name2", Ascending: true}},
+				SortFields: []ast.SortField{{Uname: "name", Name: "name", Ascending: false}, {Uname: "name2", Name: "name2", Ascending: true}},
 			},
 		},
 
@@ -1090,7 +1090,7 @@ func TestParser_ParseStatement(t *testing.T) {
 						},
 					},
 				},
-				SortFields: []ast.SortField{{Name: "name", Ascending: false}, {Name: "name2", Ascending: true}},
+				SortFields: []ast.SortField{{Uname: "name", Name: "name", Ascending: false}, {Uname: "name2", Name: "name2", Ascending: true}},
 			},
 		},
 

+ 25 - 31
internal/xsql/valuer.go

@@ -22,7 +22,6 @@ import (
 	"math"
 	"reflect"
 	"sort"
-	"strings"
 	"time"
 )
 
@@ -34,8 +33,8 @@ var implicitValueFuncs = map[string]bool{
 // Valuer is the interface that wraps the Value() method.
 type Valuer interface {
 	// Value returns the value and existence flag for a given key.
-	Value(key string) (interface{}, bool)
-	Meta(key string) (interface{}, bool)
+	Value(key, table string) (interface{}, bool)
+	Meta(key, table string) (interface{}, bool)
 	AppendAlias(key string, value interface{}) bool
 }
 
@@ -73,21 +72,14 @@ type WildcardValuer struct {
 	Data Wildcarder
 }
 
-//TODO deal with wildcard of a stream, e.g. SELECT Table.* from Table inner join Table1
-func (wv *WildcardValuer) Value(key string) (interface{}, bool) {
-	if key == "" {
-		return wv.Data.All(key)
-	} else {
-		a := strings.Index(key, ast.COLUMN_SEPARATOR+"*")
-		if a <= 0 {
-			return nil, false
-		} else {
-			return wv.Data.All(key[:a])
-		}
+func (wv *WildcardValuer) Value(key, table string) (interface{}, bool) {
+	if key == "*" {
+		return wv.Data.All(table)
 	}
+	return nil, false
 }
 
-func (wv *WildcardValuer) Meta(string) (interface{}, bool) {
+func (wv *WildcardValuer) Meta(_, _ string) (interface{}, bool) {
 	return nil, false
 }
 
@@ -129,7 +121,7 @@ func (ms *MultiSorter) Less(i, j int) bool {
 	p, q := ms.values[i], ms.values[j]
 	v := &ValuerEval{Valuer: MultiValuer(ms.valuer)}
 	for _, field := range ms.fields {
-		n := field.Name
+		n := field.Uname
 		vp, _ := p[n]
 		vq, _ := q[n]
 		if vp == nil && vq != nil {
@@ -169,8 +161,7 @@ func (ms *MultiSorter) Sort(data SortingData) error {
 		p := data.Index(i)
 		vep := &ValuerEval{Valuer: MultiValuer(p, ms.valuer)}
 		for j, field := range ms.fields {
-			n := field.Name
-			vp, _ := vep.Valuer.Value(n)
+			vp, _ := vep.Valuer.Value(field.Name, string(field.StreamName))
 			if err, ok := vp.(error); ok {
 				return err
 			} else {
@@ -180,7 +171,7 @@ func (ms *MultiSorter) Sort(data SortingData) error {
 				if err := validate(types[j], vp); err != nil {
 					return err
 				} else {
-					ms.values[i][n] = vp
+					ms.values[i][field.Uname] = vp
 				}
 			}
 		}
@@ -256,18 +247,18 @@ func MultiValuer(valuers ...Valuer) Valuer {
 
 type multiValuer []Valuer
 
-func (a multiValuer) Value(key string) (interface{}, bool) {
+func (a multiValuer) Value(key, table string) (interface{}, bool) {
 	for _, valuer := range a {
-		if v, ok := valuer.Value(key); ok {
+		if v, ok := valuer.Value(key, table); ok {
 			return v, true
 		}
 	}
 	return nil, false
 }
 
-func (a multiValuer) Meta(key string) (interface{}, bool) {
+func (a multiValuer) Meta(key, table string) (interface{}, bool) {
 	for _, valuer := range a {
-		if v, ok := valuer.Meta(key); ok {
+		if v, ok := valuer.Meta(key, table); ok {
 			return v, true
 		}
 	}
@@ -422,16 +413,19 @@ func (v *ValuerEval) Eval(expr ast.Expr) interface{} {
 		}
 		return nil
 	case *ast.FieldRef:
-		var n string
+		var (
+			t, n string
+		)
 		if expr.IsAlias() { // alias is renamed internally to avoid accidentally evaled as a col with the same name
-			n = fmt.Sprintf("%s%s", PRIVATE_PREFIX, expr.Name)
+			n = PRIVATE_PREFIX + expr.Name
 		} else if expr.StreamName == ast.DefaultStream {
 			n = expr.Name
 		} else {
-			n = fmt.Sprintf("%s%s%s", string(expr.StreamName), ast.COLUMN_SEPARATOR, expr.Name)
+			t = string(expr.StreamName)
+			n = expr.Name
 		}
 		if n != "" {
-			val, ok := v.Valuer.Value(n)
+			val, ok := v.Valuer.Value(n, t)
 			if ok {
 				return val
 			}
@@ -444,22 +438,22 @@ func (v *ValuerEval) Eval(expr ast.Expr) interface{} {
 		return nil
 	case *ast.MetaRef:
 		if expr.StreamName == "" || expr.StreamName == ast.DefaultStream {
-			val, _ := v.Valuer.Meta(expr.Name)
+			val, _ := v.Valuer.Meta(expr.Name, "")
 			return val
 		} else {
 			//The field specified with stream source
-			val, _ := v.Valuer.Meta(string(expr.StreamName) + ast.COLUMN_SEPARATOR + expr.Name)
+			val, _ := v.Valuer.Meta(expr.Name, string(expr.StreamName))
 			return val
 		}
 	case *ast.JsonFieldRef:
-		val, ok := v.Valuer.Value(expr.Name)
+		val, ok := v.Valuer.Value(expr.Name, "")
 		if ok {
 			return val
 		} else {
 			return nil
 		}
 	case *ast.Wildcard:
-		val, _ := v.Valuer.Value("")
+		val, _ := v.Valuer.Value("*", "")
 		return val
 	case *ast.CaseExpr:
 		return v.evalCase(expr)

+ 4 - 2
pkg/ast/statement.go

@@ -177,8 +177,10 @@ type Window struct {
 }
 
 type SortField struct {
-	Name      string
-	Ascending bool
+	Name       string
+	StreamName StreamName
+	Uname      string // unique name of a field
+	Ascending  bool
 
 	Expr
 }