diff --git a/cmd/db-server/main.go b/cmd/db-server/main.go index 0bd06cdec8501fc780590c003c46f8e9ae706e48..6c00a34731eff07bc17d82e5cca76a4cf86187bc 100644 --- a/cmd/db-server/main.go +++ b/cmd/db-server/main.go @@ -59,14 +59,14 @@ func cleanup() { } func main() { - if len(os.Args) < 2{ - fmt.Printf("Usage: %s configFile") + if len(os.Args) < 2 { + fmt.Printf("Usage: %s configFile", os.Args[0]) os.Exit(-1) } flag.Parse() config.InitializeConfig(*configPath, *configCheck, *configStrict, reloadConfig, overrideConfig) config.GlobalSystemVariables.LoadInitialValues() - config.LoadvarsConfigFromFile(os.Args[1],&config.GlobalSystemVariables) + config.LoadvarsConfigFromFile(os.Args[1], &config.GlobalSystemVariables) createServer() registerSignalHandlers() runServer() diff --git a/go.mod b/go.mod index 4b4f27ba9999b347795207bbe3546bac5adbd443..c996275758c1da7dbb1afc74f57db20d0debf1d0 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,10 @@ go 1.15 require ( github.com/BurntSushi/toml v0.3.1 github.com/aws/aws-sdk-go v1.37.14 - github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d + github.com/cockroachdb/pebble v0.0.0-20210526183633-dd2a545f5d75 // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 - github.com/fagongzi/goetty v2.0.2+incompatible - github.com/fagongzi/util v0.0.0-20201116094402-221cc40c4593 github.com/frankban/quicktest v1.11.3 // indirect - github.com/go-sql-driver/mysql v1.5.0 // indirect - github.com/gogo/protobuf v1.3.2 - github.com/golang/protobuf v1.5.2 // indirect - github.com/google/uuid v1.2.0 // indirect - github.com/klauspost/compress v1.11.7 // indirect + github.com/google/uuid v1.2.0 github.com/pierrec/lz4 v2.6.0+incompatible github.com/pilosa/pilosa v1.4.0 github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 @@ -25,5 +19,5 @@ require ( github.com/traetox/goaio v0.0.0-20171005222435-46641abceb17 go.uber.org/zap v1.15.0 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f - golang.org/x/text v0.3.3 // indirect + golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174 // indirect ) diff --git a/pkg/config/config.toml b/pkg/config/config.toml new file mode 100644 index 0000000000000000000000000000000000000000..e79411e031253506282f7a448e310beca5ae5e59 --- /dev/null +++ b/pkg/config/config.toml @@ -0,0 +1,139 @@ + +# Code generated by tool; DO NOT EDIT. + + + +# Name: boolSet1 +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [true] +# Comment: boolSet1 +# UpdateMode: dynamic + boolSet1=true + + + +# Name: boolSet2 +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [false] +# Comment: boolSet2 +# UpdateMode: hotload + boolSet2=false + + + +# Name: boolSet3 +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [] +# Comment: boolSet3 +# UpdateMode: dynamic + boolSet3= false + + + +# Name: stringSet1 +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [ss1 ss2 ss3] +# Comment: stringSet1 +# UpdateMode: dynamic + stringSet1= "ss1" + + + +# Name: stringSet2 +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [] +# Comment: stringSet2 +# UpdateMode: dynamic + stringSet2= "" + + + +# Name: int64set1 +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: set +# Values: [1 2 3 4 5 6] +# Comment: int64Set1 +# UpdateMode: dynamic + int64set1=1 + + + + + +# Name: int64set3 +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: set +# Values: [] +# Comment: int64Set3 +# UpdateMode: dynamic + int64set3= 0 + + + +# Name: int64Range1 +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: range +# Values: [1000 0 10000] +# Comment: int64Range1 +# UpdateMode: dynamic + int64Range1=1000 + + + +# Name: float64set1 +# Scope: [global] +# Access: [file] +# DataType: float64 +# DomainType: set +# Values: [1.0 2.0 3.0 4.00 5.0 6.0] +# Comment: float64Set1 +# UpdateMode: dynamic + float64set1=1.0 + + + + + +# Name: float64set3 +# Scope: [global] +# Access: [file] +# DataType: float64 +# DomainType: set +# Values: [] +# Comment: float64Set3 +# UpdateMode: dynamic + float64set3= 0.0 + + + +# Name: float64Range1 +# Scope: [global] +# Access: [file] +# DataType: float64 +# DomainType: range +# Values: [1000.01 0.02 10000.03] +# Comment: float64Range1 +# UpdateMode: dynamic + float64Range1=1000.01 + diff --git a/pkg/config/config_template.go b/pkg/config/config_template.go index 492305ea30de28b03fdd327cdd2b9b089d0701c1..a690502358bf030016b787a89a6d4ba86d3d1a15 100644 --- a/pkg/config/config_template.go +++ b/pkg/config/config_template.go @@ -1338,6 +1338,25 @@ func (cfgi *ConfigurationFileGeneratorImpl) Generate() error { return nil } +/** +load items from configuration file periodly. + */ +type ConfigurationFileHotLoader interface { + /** + register a configuration file into the loader. + path : the path of the configuration file + period: load the configration every period + configObject: the target that will be updated + */ + Register(path string,period int64,configObject interface{}) + + /** + unregister a configuration file from the loader. + the configuration file will be loaded again. + */ + Unregister(path string) +} + func NewConfigurationFileGenerator(defFileName string)ConfigurationFileGenerator{ return &ConfigurationFileGeneratorImpl{ parameterDefinitionFileName: defFileName, diff --git a/pkg/config/config_template_test.go b/pkg/config/config_template_test.go index 8d05b1e3bf87be76e9652c89f7599f3d0b1f0500..3f08f7b775f5769d71abfbd0fa11e643cceaf36d 100644 --- a/pkg/config/config_template_test.go +++ b/pkg/config/config_template_test.go @@ -12,14 +12,14 @@ import ( ) type par struct { - Name string `toml:"Name"` + Name string `toml:"Name"` } type Pars struct { Par []par } func TestToml(t *testing.T) { - blob :=` + blob := ` [[par]] Name = "Thunder Road" @@ -37,14 +37,14 @@ func TestToml(t *testing.T) { } } -func compareArray(A,B []string)bool{ - if len(A) != len(B){ +func compareArray(A, B []string) bool { + if len(A) != len(B) { return false } sort.Strings(A) sort.Strings(B) - for i:=0; i < len(A);i++{ + for i := 0; i < len(A); i++ { if A[i] != B[i] { return false } @@ -75,67 +75,67 @@ func TestParameter(t *testing.T) { update-mode = "fix" ` var results = map[string]parameter{ - "autocommit":parameter{ - Name : "autocommit", - Scope : []string{"global", "session"}, - Access : []string{"file"}, - DataType: "bool", - DomainType : "set", - Values: []string{"true"}, - Comment : "autocommit", - UpdateMode:"dynamic", - }, - "back-log":parameter{ - Name : "back-log", - Scope : []string{"global"}, - Access : []string{"file"}, - DataType: "int64", - DomainType : "range", - Values : []string{"-1","1","65535"}, - Comment : "back-log", - UpdateMode:"fix", + "autocommit": parameter{ + Name: "autocommit", + Scope: []string{"global", "session"}, + Access: []string{"file"}, + DataType: "bool", + DomainType: "set", + Values: []string{"true"}, + Comment: "autocommit", + UpdateMode: "dynamic", + }, + "back-log": parameter{ + Name: "back-log", + Scope: []string{"global"}, + Access: []string{"file"}, + DataType: "int64", + DomainType: "range", + Values: []string{"-1", "1", "65535"}, + Comment: "back-log", + UpdateMode: "fix", }, } var paras parameters if metadata, err := toml.Decode(blob, ¶s); err != nil { t.Errorf("error:%v \n", err) - }else if undecoded := metadata.Undecoded() ; len(undecoded) > 0 && err == nil{ + } else if undecoded := metadata.Undecoded(); len(undecoded) > 0 && err == nil { for _, item := range undecoded { - t.Errorf("undecoded %s\n",item.String()) + t.Errorf("undecoded %s\n", item.String()) } } for _, p := range paras.Parameter { par := results[p.Name] if p.Name != par.Name || - !compareArray(p.Scope , par.Scope) || - !compareArray(p.Access , par.Access) || + !compareArray(p.Scope, par.Scope) || + !compareArray(p.Access, par.Access) || p.DataType != par.DataType || p.DomainType != par.DomainType || - !compareArray(p.Values,par.Values) || + !compareArray(p.Values, par.Values) || p.Comment != par.Comment || - p.UpdateMode != par.UpdateMode{ - t.Errorf("toml decode parameter failed.") - } + p.UpdateMode != par.UpdateMode { + t.Errorf("toml decode parameter failed.") + } } } func Test_isAsciiChar(t *testing.T) { cases := [][]byte{ - {'a', 'j','z', 'A','J', 'Z','_'}, - {'<','=','>','+','{','[','@',0,' ','~'}, + {'a', 'j', 'z', 'A', 'J', 'Z', '_'}, + {'<', '=', '>', '+', '{', '[', '@', 0, ' ', '~'}, } - results :=[]bool{ + results := []bool{ true, false, } - for i:=0; i < len(results);i++{ - for _, x := range cases[i]{ + for i := 0; i < len(results); i++ { + for _, x := range cases[i] { r := isAsciiChar(x) - if r != results[i]{ - t.Errorf("isAsciiChar failed. %d %c %v %v",i,x,r,results[i]) + if r != results[i] { + t.Errorf("isAsciiChar failed. %d %c %v %v", i, x, r, results[i]) return } } @@ -144,20 +144,20 @@ func Test_isAsciiChar(t *testing.T) { func Test_isAsciiDigit(t *testing.T) { cases := [][]byte{ - {'0', '1','7', '8','9'}, - {'<','=','>','+','{','[','@',0,' ','~','/',':'}, + {'0', '1', '7', '8', '9'}, + {'<', '=', '>', '+', '{', '[', '@', 0, ' ', '~', '/', ':'}, } - results :=[]bool{ + results := []bool{ true, false, } - for i:=0; i < len(results);i++{ - for _, x := range cases[i]{ + for i := 0; i < len(results); i++ { + for _, x := range cases[i] { r := isAsciiDigit(x) - if r != results[i]{ - t.Errorf("isAsciiDigit failed. %d %c %v %v",i,x,r,results[i]) + if r != results[i] { + t.Errorf("isAsciiDigit failed. %d %c %v %v", i, x, r, results[i]) return } } @@ -166,19 +166,19 @@ func Test_isAsciiDigit(t *testing.T) { func Test_isGoIdentifier(t *testing.T) { cases := [][]string{ - {"a", "j","z", "_"}, - {"A","J", "Z"}, - {"<","=",">","+","{","[","@","0"," ","~",""}, - {"a0", "j0","z0", "_0"}, - {"A0","J0", "Z0"}, - {"a<", "j<","z<", "_<"}, - {"A<","J<", "Z<"}, - {"ap", "jp","zp", "_p"}, - {"Ap","Jp", "Zp"}, - {"pA","pJ", "pZ"}, - } - - results :=[]bool{ + {"a", "j", "z", "_"}, + {"A", "J", "Z"}, + {"<", "=", ">", "+", "{", "[", "@", "0", " ", "~", ""}, + {"a0", "j0", "z0", "_0"}, + {"A0", "J0", "Z0"}, + {"a<", "j<", "z<", "_<"}, + {"A<", "J<", "Z<"}, + {"ap", "jp", "zp", "_p"}, + {"Ap", "Jp", "Zp"}, + {"pA", "pJ", "pZ"}, + } + + results := []bool{ true, false, false, @@ -191,11 +191,11 @@ func Test_isGoIdentifier(t *testing.T) { true, } - for i:=0; i < len(results);i++{ - for _, x := range cases[i]{ + for i := 0; i < len(results); i++ { + for _, x := range cases[i] { r := isGoIdentifier(x) - if r != results[i]{ - t.Errorf("isGoIdentifier failed. %d %s %v %v",i,x,r,results[i]) + if r != results[i] { + t.Errorf("isGoIdentifier failed. %d %s %v %v", i, x, r, results[i]) return } } @@ -204,19 +204,19 @@ func Test_isGoIdentifier(t *testing.T) { func Test_isGoStructAndInterfaceIdentifier(t *testing.T) { cases := [][]string{ - {"a", "j","z", "_"}, - {"A","J", "Z"}, - {"<","=",">","+","{","[","@","0"," ","~",""}, - {"a0", "j0","z0", "_0"}, - {"A0","J0", "Z0"}, - {"a<", "j<","z<", "_<"}, - {"A<","J<", "Z<"}, - {"ap", "jp","zp", "_p"}, - {"Ap","Jp", "Zp"}, - {"pA","pJ", "pZ"}, - } - - results :=[]bool{ + {"a", "j", "z", "_"}, + {"A", "J", "Z"}, + {"<", "=", ">", "+", "{", "[", "@", "0", " ", "~", ""}, + {"a0", "j0", "z0", "_0"}, + {"A0", "J0", "Z0"}, + {"a<", "j<", "z<", "_<"}, + {"A<", "J<", "Z<"}, + {"ap", "jp", "zp", "_p"}, + {"Ap", "Jp", "Zp"}, + {"pA", "pJ", "pZ"}, + } + + results := []bool{ true, true, false, @@ -229,44 +229,44 @@ func Test_isGoStructAndInterfaceIdentifier(t *testing.T) { true, } - for i:=0; i < len(results);i++{ - for _, x := range cases[i]{ + for i := 0; i < len(results); i++ { + for _, x := range cases[i] { r := isGoStructAndInterfaceIdentifier(x) - if r != results[i]{ - t.Errorf("isGoIdentifier failed. %d %s %v %v",i,x,r,results[i]) + if r != results[i] { + t.Errorf("isGoIdentifier failed. %d %s %v %v", i, x, r, results[i]) return } } } } -func Test_isSubset(t *testing.T){ +func Test_isSubset(t *testing.T) { A := [][]string{ - {"a","b","c"}, + {"a", "b", "c"}, {}, - {"a","a"}, - {"a","e"}, - {"a","b","c","e"}, - {"a","b"}, - {"b","c"}, - {"a","c"}, + {"a", "a"}, + {"a", "e"}, + {"a", "b", "c", "e"}, + {"a", "b"}, + {"b", "c"}, + {"a", "c"}, {"a"}, {"b"}, {"c"}, } B := [][]string{ - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, - {"a","b","c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, + {"a", "b", "c"}, } results := []bool{ @@ -283,25 +283,25 @@ func Test_isSubset(t *testing.T){ true, } - for i:=0; i < len(results);i++{ - r := isSubset(A[i],B[i]) - if r != results[i]{ - t.Errorf("isSubset failed. %d %s %s %v %v",i,A[i],B[i],r,results[i]) + for i := 0; i < len(results); i++ { + r := isSubset(A[i], B[i]) + if r != results[i] { + t.Errorf("isSubset failed. %d %s %s %v %v", i, A[i], B[i], r, results[i]) return } } } -func Test_isScope(t *testing.T){ +func Test_isScope(t *testing.T) { A := [][]string{ - {"session","global","c"}, + {"session", "global", "c"}, {}, - {"session","session"}, - {"session","e"}, - {"session","global","c","e"}, - {"session","global"}, - {"global","c"}, - {"session","c"}, + {"session", "session"}, + {"session", "e"}, + {"session", "global", "c", "e"}, + {"session", "global"}, + {"global", "c"}, + {"session", "c"}, {"session"}, {"global"}, {"c"}, @@ -321,25 +321,25 @@ func Test_isScope(t *testing.T){ false, } - for i:=0; i < len(results);i++{ + for i := 0; i < len(results); i++ { r := isScope(A[i]) - if r != results[i]{ - t.Errorf("isScope failed. %d %s %v %v",i,A[i],r,results[i]) + if r != results[i] { + t.Errorf("isScope failed. %d %s %v %v", i, A[i], r, results[i]) return } } } -func Test_isAccess(t *testing.T){ +func Test_isAccess(t *testing.T) { A := [][]string{ - {"cmd","file","c"}, + {"cmd", "file", "c"}, {}, - {"cmd","cmd"}, - {"cmd","e"}, - {"cmd","file","c","e"}, - {"cmd","file"}, - {"file","c"}, - {"cmd","c"}, + {"cmd", "cmd"}, + {"cmd", "e"}, + {"cmd", "file", "c", "e"}, + {"cmd", "file"}, + {"file", "c"}, + {"cmd", "c"}, {"cmd"}, {"file"}, {"c"}, @@ -359,19 +359,19 @@ func Test_isAccess(t *testing.T){ false, } - for i:=0; i < len(results);i++{ + for i := 0; i < len(results); i++ { r := isAccess(A[i]) - if r != results[i]{ - t.Errorf("isAccess failed. %d %s %v %v",i,A[i],r,results[i]) + if r != results[i] { + t.Errorf("isAccess failed. %d %s %v %v", i, A[i], r, results[i]) return } } } -func Test_isDataType(t *testing.T){ +func Test_isDataType(t *testing.T) { A := []string{ "string", "int64", "float64", "bool", - "A","B","C","D", + "A", "B", "C", "D", } results := []bool{ @@ -385,20 +385,20 @@ func Test_isDataType(t *testing.T){ false, } - for i:=0; i < len(results);i++{ + for i := 0; i < len(results); i++ { r := isDataType(A[i]) - if r != results[i]{ - t.Errorf("isDataType failed. %d %s %v %v",i,A[i],r,results[i]) + if r != results[i] { + t.Errorf("isDataType failed. %d %s %v %v", i, A[i], r, results[i]) return } } } -func Test_isDomainType(t *testing.T){ +func Test_isDomainType(t *testing.T) { A := []string{ - "set","range", + "set", "range", "string", "int64", "float64", "bool", - "A","B","C","D", + "A", "B", "C", "D", } results := []bool{ @@ -414,97 +414,97 @@ func Test_isDomainType(t *testing.T){ false, } - for i:=0; i < len(results);i++{ + for i := 0; i < len(results); i++ { r := isDomainType(A[i]) - if r != results[i]{ - t.Errorf("isDataType failed. %d %s %v %v",i,A[i],r,results[i]) + if r != results[i] { + t.Errorf("isDataType failed. %d %s %v %v", i, A[i], r, results[i]) return } } } type valueCase struct { - dataType string + dataType string domainType string - values []string + values []string } -func Test_checkValues(t *testing.T){ +func Test_checkValues(t *testing.T) { A := []valueCase{ //string - {"string","set",[]string{}}, - {"string","set",[]string{"A"}}, - {"string","set",[]string{"A","A"}}, - {"string","set",[]string{"A","A","B","C"}}, - {"string","set",[]string{"A","B","C"}}, - - {"string","range",[]string{}}, - {"string","range",[]string{"A"}}, - {"string","range",[]string{"A","A"}}, - {"string","range",[]string{"A","A","B","C"}}, - {"string","range",[]string{"A","B","C"}}, + {"string", "set", []string{}}, + {"string", "set", []string{"A"}}, + {"string", "set", []string{"A", "A"}}, + {"string", "set", []string{"A", "A", "B", "C"}}, + {"string", "set", []string{"A", "B", "C"}}, + + {"string", "range", []string{}}, + {"string", "range", []string{"A"}}, + {"string", "range", []string{"A", "A"}}, + {"string", "range", []string{"A", "A", "B", "C"}}, + {"string", "range", []string{"A", "B", "C"}}, //int64 - {"int64","set",[]string{}}, - {"int64","set",[]string{"A"}}, - {"int64","set",[]string{"A","A"}}, - {"int64","set",[]string{"A","A","B","C"}}, - {"int64","set",[]string{"A","B","C"}}, - - {"int64","set",[]string{"0"}}, - {"int64","set",[]string{"0","0"}}, - {"int64","set",[]string{"0","0","1","C"}}, - {"int64","set",[]string{"0","1","2"}}, - {"int64","set",[]string{"0","1","2","0"}}, - - {"int64","range",[]string{"0"}}, - {"int64","range",[]string{"0","1"}}, - {"int64","range",[]string{"0","1","2"}}, - {"int64","range",[]string{"1","0","2"}}, - {"int64","range",[]string{"3","1","2"}}, - {"int64","range",[]string{"5","1","9"}}, + {"int64", "set", []string{}}, + {"int64", "set", []string{"A"}}, + {"int64", "set", []string{"A", "A"}}, + {"int64", "set", []string{"A", "A", "B", "C"}}, + {"int64", "set", []string{"A", "B", "C"}}, + + {"int64", "set", []string{"0"}}, + {"int64", "set", []string{"0", "0"}}, + {"int64", "set", []string{"0", "0", "1", "C"}}, + {"int64", "set", []string{"0", "1", "2"}}, + {"int64", "set", []string{"0", "1", "2", "0"}}, + + {"int64", "range", []string{"0"}}, + {"int64", "range", []string{"0", "1"}}, + {"int64", "range", []string{"0", "1", "2"}}, + {"int64", "range", []string{"1", "0", "2"}}, + {"int64", "range", []string{"3", "1", "2"}}, + {"int64", "range", []string{"5", "1", "9"}}, //float64 - {"float64","set",[]string{}}, - {"float64","set",[]string{"A"}}, - {"float64","set",[]string{"A","A"}}, - {"float64","set",[]string{"A","A","B","C"}}, - {"float64","set",[]string{"A","B","C"}}, - - {"float64","set",[]string{"0.1"}}, - {"float64","set",[]string{"0.1","0.1"}}, - {"float64","set",[]string{"0","0","1","C"}}, - {"float64","set",[]string{"0","1","2"}}, - {"float64","set",[]string{"0","1","2","0"}}, - - {"float64","range",[]string{"0"}}, - {"float64","range",[]string{"0","1"}}, - {"float64","range",[]string{"0","1","2"}}, - {"float64","range",[]string{"1","0","2"}}, - {"float64","range",[]string{"3","1","2"}}, - {"float64","range",[]string{"5","1","9"}}, + {"float64", "set", []string{}}, + {"float64", "set", []string{"A"}}, + {"float64", "set", []string{"A", "A"}}, + {"float64", "set", []string{"A", "A", "B", "C"}}, + {"float64", "set", []string{"A", "B", "C"}}, + + {"float64", "set", []string{"0.1"}}, + {"float64", "set", []string{"0.1", "0.1"}}, + {"float64", "set", []string{"0", "0", "1", "C"}}, + {"float64", "set", []string{"0", "1", "2"}}, + {"float64", "set", []string{"0", "1", "2", "0"}}, + + {"float64", "range", []string{"0"}}, + {"float64", "range", []string{"0", "1"}}, + {"float64", "range", []string{"0", "1", "2"}}, + {"float64", "range", []string{"1", "0", "2"}}, + {"float64", "range", []string{"3", "1", "2"}}, + {"float64", "range", []string{"5", "1", "9"}}, //bool - {"bool","set",[]string{}}, - {"bool","set",[]string{"A"}}, - {"bool","set",[]string{"A","A"}}, - {"bool","set",[]string{"A","A","B","C"}}, - {"bool","set",[]string{"A","B","C"}}, - - {"bool","set",[]string{"0.1"}}, - {"bool","set",[]string{"false"}}, - {"bool","set",[]string{"off"}}, - {"bool","set",[]string{"true"}}, - {"bool","set",[]string{"on"}}, - - {"bool","range",[]string{"0","1","2","0"}}, - {"bool","set",[]string{"FALSE"}}, - {"bool","set",[]string{"OFF"}}, - {"bool","set",[]string{"TRUE"}}, - {"bool","set",[]string{"ON"}}, + {"bool", "set", []string{}}, + {"bool", "set", []string{"A"}}, + {"bool", "set", []string{"A", "A"}}, + {"bool", "set", []string{"A", "A", "B", "C"}}, + {"bool", "set", []string{"A", "B", "C"}}, + + {"bool", "set", []string{"0.1"}}, + {"bool", "set", []string{"false"}}, + {"bool", "set", []string{"off"}}, + {"bool", "set", []string{"true"}}, + {"bool", "set", []string{"on"}}, + + {"bool", "range", []string{"0", "1", "2", "0"}}, + {"bool", "set", []string{"FALSE"}}, + {"bool", "set", []string{"OFF"}}, + {"bool", "set", []string{"TRUE"}}, + {"bool", "set", []string{"ON"}}, //x - {"x","set",[]string{"FALSE"}}, + {"x", "set", []string{"FALSE"}}, } results := []bool{ @@ -584,10 +584,10 @@ func Test_checkValues(t *testing.T){ false, } - for i:=0; i < len(results);i++{ - r := checkValues(A[i].dataType,A[i].domainType,A[i].values) - if r != results[i]{ - t.Errorf("checkValues failed. %d %s %v %v",i,A[i],r,results[i]) + for i := 0; i < len(results); i++ { + r := checkValues(A[i].dataType, A[i].domainType, A[i].values) + if r != results[i] { + t.Errorf("checkValues failed. %d %s %v %v", i, A[i], r, results[i]) return } } @@ -602,11 +602,11 @@ func Test_hasDuplicateValue(t *testing.T) { args args want bool }{ - {"t1",args{[]string{"A","B","A"}},true}, - {"t2",args{[]string{"A","B","C"}},false}, - {"t3",args{[]string{"A"}},false}, - {"t4",args{[]string{"A","A"}},true}, - {"t5",args{[]string{}},false}, + {"t1", args{[]string{"A", "B", "A"}}, true}, + {"t2", args{[]string{"A", "B", "C"}}, false}, + {"t3", args{[]string{"A"}}, false}, + {"t4", args{[]string{"A", "A"}}, true}, + {"t5", args{[]string{}}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -626,11 +626,11 @@ func Test_hasDuplicateValueInt64(t *testing.T) { args args want bool }{ - {"t1",args{[]int64{0,1,0}},true}, - {"t2",args{[]int64{0,1,2}},false}, - {"t3",args{[]int64{0}},false}, - {"t4",args{[]int64{0,0}},true}, - {"t5",args{[]int64{}},false}, + {"t1", args{[]int64{0, 1, 0}}, true}, + {"t2", args{[]int64{0, 1, 2}}, false}, + {"t3", args{[]int64{0}}, false}, + {"t4", args{[]int64{0, 0}}, true}, + {"t5", args{[]int64{}}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -650,11 +650,11 @@ func Test_hasDuplicateValueFloat64(t *testing.T) { args args want bool }{ - {"t1",args{[]float64{0,1,0}},true}, - {"t2",args{[]float64{0,1,2}},false}, - {"t3",args{[]float64{0}},false}, - {"t4",args{[]float64{0,0}},true}, - {"t5",args{[]float64{}},false}, + {"t1", args{[]float64{0, 1, 0}}, true}, + {"t2", args{[]float64{0, 1, 2}}, false}, + {"t3", args{[]float64{0}}, false}, + {"t4", args{[]float64{0, 0}}, true}, + {"t5", args{[]float64{}}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -674,8 +674,8 @@ func Test_parameters_LoadParametersDefinition(t *testing.T) { args args wantErr bool }{ - {"t1",args{"test/t1.toml"},false}, - {"t2",args{"test/t2.toml"},true}, + {"t1", args{"test/t1.toml"}, false}, + {"t2", args{"test/t2.toml"}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -691,6 +691,8 @@ func Test_parameters_LoadParametersDefinitionFromString(t *testing.T) { t1 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" + operation-file-name = "parameters" + config-file-name = "config" [[parameter]] name = "autocommit" @@ -705,6 +707,8 @@ func Test_parameters_LoadParametersDefinitionFromString(t *testing.T) { t2 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "autocommit@" @@ -719,6 +723,8 @@ config-struct-name = "configuration" t3 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "autocommit" @@ -733,6 +739,8 @@ config-struct-name = "configuration" t4 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "autocommit" @@ -747,6 +755,8 @@ config-struct-name = "configuration" t5 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "autocommit" @@ -761,6 +771,8 @@ config-struct-name = "configuration" t6 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "autocommit" @@ -775,6 +787,8 @@ config-struct-name = "configuration" t7 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "count" @@ -789,6 +803,8 @@ config-struct-name = "configuration" t8 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "count" @@ -811,9 +827,11 @@ config-struct-name = "configuration" update-mode = "fix" ` - t9 :=` + t9 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "boolset1" @@ -826,9 +844,11 @@ config-struct-name = "configuration" update-mode = "dynamic" ` - t10 :=` + t10 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "int64set1" @@ -841,9 +861,11 @@ config-struct-name = "configuration" update-mode = "dynamic" ` - t11 :=` + t11 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "float64set1" @@ -856,9 +878,11 @@ config-struct-name = "configuration" update-mode = "dynamic" ` - t12 :=` + t12 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" +operation-file-name = "parameters" +config-file-name = "config" [[parameter]] name = "stringset1" @@ -878,18 +902,18 @@ config-struct-name = "configuration" args args wantErr bool }{ - {"t1",args{t1},false}, - {"t2",args{t2},true}, - {"t3",args{t3},true}, - {"t4",args{t4},true}, - {"t5",args{t5},true}, - {"t6",args{t6},false}, - {"t7",args{t7},false}, - {"t8",args{t8},true}, - {"t9",args{t9},false}, - {"t10",args{t10},false}, - {"t11",args{t11},false}, - {"t12",args{t12},false}, + {"t1", args{t1}, false}, + {"t2", args{t2}, true}, + {"t3", args{t3}, true}, + {"t4", args{t4}, true}, + {"t5", args{t5}, true}, + {"t6", args{t6}, false}, + {"t7", args{t7}, false}, + {"t8", args{t8}, true}, + {"t9", args{t9}, false}, + {"t10", args{t10}, false}, + {"t11", args{t11}, false}, + {"t12", args{t12}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -906,7 +930,7 @@ type Inventory struct { Count uint } -var tmplStr = ` +var tmplStr = ` // Code generated by tool; DO NOT EDIT. package config @@ -941,7 +965,7 @@ type {{.ConfigurationStructName}} struct{ {{ printf "/**\n\tName:\t%s\n\tScope:\t%s\n\tAccess:\t%s\n\tDataType:\t%s\n\tDomainType:\t%s\n\tValues:\t%s\n\tComment:\t%s\n\tUpdateMode:\t%s\n\t*/" .Name .Scope .Access .DataType .DomainType .Values .Comment .UpdateMode }} - {{ printf "%s %s `+"`toml:"+`\"%s\"`+"`"+`" .CapitalName .DataType .Name }} + {{ printf "%s %s ` + "`toml:" + `\"%s\"` + "`" + `" .CapitalName .DataType .Name }} {{end}} {{end}} @@ -1296,13 +1320,13 @@ func (ap * {{.ParameterStructName}} ) UpdateParametersWithConfiguration(config * } ` -func Test_template(t *testing.T){ +func Test_template(t *testing.T) { var paras = parameters{ - ParameterStructName: "AllParameters", + ParameterStructName: "AllParameters", ConfigurationStructName: "configuration", Parameter: []parameter{ { - Name: "boolSet1", + Name: "boolSet1", Scope: []string{"global", "session"}, Access: []string{"file"}, DataType: "bool", @@ -1312,7 +1336,7 @@ func Test_template(t *testing.T){ UpdateMode: "dynamic", }, { - Name: "boolRange1", + Name: "boolRange1", Scope: []string{"global", "session"}, Access: []string{"file"}, DataType: "bool", @@ -1322,97 +1346,97 @@ func Test_template(t *testing.T){ UpdateMode: "dynamic", }, { - Name: "stringSet1", + Name: "stringSet1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "string", DomainType: "set", - Values: []string{"localhost","127.0.0.1",}, + Values: []string{"localhost", "127.0.0.1"}, Comment: "stringSet1", UpdateMode: "dynamic", }, { - Name: "stringRange1", + Name: "stringRange1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "string", DomainType: "range", - Values: []string{"localhost","127.0.0.1",}, + Values: []string{"localhost", "127.0.0.1"}, Comment: "stringRange1", UpdateMode: "dynamic", }, { - Name: "int64set1", + Name: "int64set1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "int64", DomainType: "set", - Values: []string{"-1","2","65535"}, + Values: []string{"-1", "2", "65535"}, Comment: "int64set1", UpdateMode: "dynamic", }, { - Name: "int64range1", + Name: "int64range1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "int64", DomainType: "range", - Values: []string{"-1","-1","65535"}, + Values: []string{"-1", "-1", "65535"}, Comment: "int64range1", UpdateMode: "dynamic", }, { - Name: "int64X1", + Name: "int64X1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "int64", DomainType: "X", - Values: []string{"-1","-1","65535"}, + Values: []string{"-1", "-1", "65535"}, Comment: "int64X1", UpdateMode: "dynamic", }, { - Name: "float64set1", + Name: "float64set1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "float64", DomainType: "set", - Values: []string{"-1.01","2.02","65535.03"}, + Values: []string{"-1.01", "2.02", "65535.03"}, Comment: "float64set1", UpdateMode: "dynamic", }, { - Name: "float64range1", + Name: "float64range1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "float64", DomainType: "range", - Values: []string{"-2.02","-1.01","65535.03"}, + Values: []string{"-2.02", "-1.01", "65535.03"}, Comment: "float64range1", UpdateMode: "dynamic", }, { - Name: "float64X1", + Name: "float64X1", Scope: []string{"global"}, Access: []string{"file"}, DataType: "float64", DomainType: "X", - Values: []string{"-1","-1","65535"}, + Values: []string{"-1", "-1", "65535"}, Comment: "float64X1", UpdateMode: "dynamic", }, { - Name: "float64set2", + Name: "float64set2", Scope: []string{"global"}, Access: []string{"file"}, DataType: "float64", DomainType: "set", - Values: []string{"-1","-1","65535"}, + Values: []string{"-1", "-1", "65535"}, Comment: "float64set2", UpdateMode: "fix", }, { - Name: "boolSet2", + Name: "boolSet2", Scope: []string{"global", "session"}, Access: []string{"file"}, DataType: "bool", @@ -1422,7 +1446,7 @@ func Test_template(t *testing.T){ UpdateMode: "dynamic", }, { - Name: "boolSet3", + Name: "boolSet3", Scope: []string{"global", "session"}, Access: []string{"file"}, DataType: "bool", @@ -1434,7 +1458,7 @@ func Test_template(t *testing.T){ }, } - for i :=0; i<len(paras.Parameter);i++{ + for i := 0; i < len(paras.Parameter); i++ { p := paras.Parameter[i].Name capName := p capName = string(unicode.ToUpper(rune(p[0]))) + p[1:] @@ -1442,19 +1466,23 @@ func Test_template(t *testing.T){ } tmpl, err := template.New("test").Parse(tmplStr) - if err != nil { panic(err) } + if err != nil { + panic(err) + } f, err := os.Create("parameters.go") - if err != nil{ + if err != nil { panic(err) } defer f.Close() err = tmpl.Execute(f, paras) - if err != nil { panic(err) } + if err != nil { + panic(err) + } } -var tomlTmplString=` +var tomlTmplString = ` # Code generated by tool; DO NOT EDIT. {{range $index,$param := .Parameter}} {{ if ne .UpdateMode "fix"}} @@ -1485,7 +1513,7 @@ var tomlTmplString=` {{end}} ` -var testOperationTmpl=` +var testOperationTmpl = ` // Code generated by tool; DO NOT EDIT. package config @@ -1515,7 +1543,7 @@ func is{{.ConfigurationStructName}}Equal(c1,c2 {{.ConfigurationStructName}}) boo } func Test_{{.ConfigurationStructName}}_LoadConfigurationFromString(t *testing.T) { - t1 := `+"`"+` + t1 := ` + "`" + ` {{range $index,$param := .Parameter}} {{ if ne .UpdateMode "fix"}} {{- with $count := len .Values -}} @@ -1539,7 +1567,7 @@ func Test_{{.ConfigurationStructName}}_LoadConfigurationFromString(t *testing.T) {{- end -}} {{end}} {{end}} -`+"`"+` +` + "`" + ` t1_config:={{.ConfigurationStructName}}{ rwlock: sync.RWMutex{}, @@ -1609,7 +1637,7 @@ func Test_{{.ConfigurationStructName}}_LoadConfigurationFromString(t *testing.T) } ` -func Test_ParameterDefinitionAndTemplate2(t *testing.T){ +func Test_ParameterDefinitionAndTemplate2(t *testing.T) { t1 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" @@ -1798,7 +1826,7 @@ func Test_ParameterDefinitionAndTemplate2(t *testing.T){ update-mode = "fix" ` - t5 :=` + t5 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" operation-file-name = "parameters" @@ -1832,7 +1860,7 @@ func Test_ParameterDefinitionAndTemplate2(t *testing.T){ update-mode = "fix" ` - t7 :=` + t7 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" operation-file-name = "parameters" @@ -1849,7 +1877,7 @@ func Test_ParameterDefinitionAndTemplate2(t *testing.T){ update-mode = "dynamic" ` - t8 :=` + t8 := ` parameter-struct-name = "AllParameters" config-struct-name = "configuration" operation-file-name = "parameters" @@ -1873,14 +1901,14 @@ func Test_ParameterDefinitionAndTemplate2(t *testing.T){ args args wantErr bool }{ - {"t1",args{t1},false}, - {"t2",args{t2},true}, - {"t3",args{t3},true}, - {"t4",args{t4},true}, - {"t5",args{t5},true}, - {"t6",args{t6},true}, - {"t7",args{t7},true}, - {"t8",args{t8},true}, + {"t1", args{t1}, false}, + {"t2", args{t2}, true}, + {"t3", args{t3}, true}, + {"t4", args{t4}, true}, + {"t5", args{t5}, true}, + {"t6", args{t6}, true}, + {"t7", args{t7}, true}, + {"t8", args{t8}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1888,54 +1916,65 @@ func Test_ParameterDefinitionAndTemplate2(t *testing.T){ if err := params.LoadParametersDefinitionFromString(tt.args.input); (err != nil) != tt.wantErr { t.Errorf("LoadParametersDefinitionFromString() error = %v, wantErr %v", err, tt.wantErr) return - }else if err!=nil{ + } else if err != nil { return } tmpl, err := template.New("test").Parse(tmplStr) - if err != nil { panic(err) } + if err != nil { + panic(err) + } f, err := os.Create("parameters.go") - if err != nil{ + if err != nil { panic(err) } defer f.Close() err = tmpl.Execute(f, params) - if err != nil { panic(err) } + if err != nil { + panic(err) + } - tomlTmpl,err := template.New("toml").Parse(tomlTmplString) - if err != nil { panic(err)} + tomlTmpl, err := template.New("toml").Parse(tomlTmplString) + if err != nil { + panic(err) + } - tomlf,err := os.Create("config.toml") - if err!= nil{ + tomlf, err := os.Create("config.toml") + if err != nil { panic(err) } defer tomlf.Close() - err = tomlTmpl.Execute(tomlf,params) - if err != nil { panic(err) } + err = tomlTmpl.Execute(tomlf, params) + if err != nil { + panic(err) + } - testTmpl,err := template.New("genTest").Parse(testOperationTmpl) - if err != nil { panic(err)} + testTmpl, err := template.New("genTest").Parse(testOperationTmpl) + if err != nil { + panic(err) + } - testf,err := os.Create("parameters_test.go") - if err!= nil{ + testf, err := os.Create("parameters_test.go") + if err != nil { panic(err) } defer testf.Close() - err = testTmpl.Execute(testf,params) - if err != nil { panic(err) } + err = testTmpl.Execute(testf, params) + if err != nil { + panic(err) + } }) } - } func Test_String(t *testing.T) { - fmt.Printf("%s \n","`toml:\"name\"`") + fmt.Printf("%s \n", "`toml:\"name\"`") } func TestNewConfigurationFileGenerator(t *testing.T) { @@ -1943,20 +1982,20 @@ func TestNewConfigurationFileGenerator(t *testing.T) { defFileName string } tests := []struct { - name string - args args + name string + args args wantErr bool }{ - {"t1",args{"test/def1.toml"},false}, - {"t2",args{"test/def2.toml"},false}, - {"t3",args{"system_vars_def.toml"},false}, + {"t1", args{"test/def1.toml"}, false}, + {"t2", args{"test/def2.toml"}, false}, + {"t3", args{"system_vars_def.toml"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gen := NewConfigurationFileGenerator(tt.args.defFileName) - if err := gen.Generate(); (err!=nil) != tt.wantErr { + if err := gen.Generate(); (err != nil) != tt.wantErr { t.Errorf("Generator() = %v, want %v", err, tt.wantErr) } }) } -} \ No newline at end of file +} diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go new file mode 100644 index 0000000000000000000000000000000000000000..83c45a4b4c946c5620b4963d3f9bfd0041236556 --- /dev/null +++ b/pkg/config/parameters.go @@ -0,0 +1,1317 @@ +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "fmt" + "github.com/BurntSushi/toml" + "sync" +) + +//all parameters in the system +type AllParameters struct { + //read and write lock + rwlock sync.RWMutex + + /** + Name: boolSet1 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [true] + Comment: boolSet1 + UpdateMode: dynamic + */ + boolSet1 bool + + /** + Name: boolSet2 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [false] + Comment: boolSet2 + UpdateMode: hotload + */ + boolSet2 bool + + /** + Name: boolSet3 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [] + Comment: boolSet3 + UpdateMode: dynamic + */ + boolSet3 bool + + /** + Name: stringSet1 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [ss1 ss2 ss3] + Comment: stringSet1 + UpdateMode: dynamic + */ + stringSet1 string + + /** + Name: stringSet2 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [] + Comment: stringSet2 + UpdateMode: dynamic + */ + stringSet2 string + + /** + Name: int64set1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [1 2 3 4 5 6] + Comment: int64Set1 + UpdateMode: dynamic + */ + int64set1 int64 + + /** + Name: int64set2 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [1 3 5 7] + Comment: int64Set2 + UpdateMode: fix + */ + int64set2 int64 + + /** + Name: int64set3 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [] + Comment: int64Set3 + UpdateMode: dynamic + */ + int64set3 int64 + + /** + Name: int64Range1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: range + Values: [1000 0 10000] + Comment: int64Range1 + UpdateMode: dynamic + */ + int64Range1 int64 + + /** + Name: float64set1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [1.0 2.0 3.0 4.00 5.0 6.0] + Comment: float64Set1 + UpdateMode: dynamic + */ + float64set1 float64 + + /** + Name: float64set2 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [1.001 3.003 5.005 7.007] + Comment: float64Set2 + UpdateMode: fix + */ + float64set2 float64 + + /** + Name: float64set3 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [] + Comment: float64Set3 + UpdateMode: dynamic + */ + float64set3 float64 + + /** + Name: float64Range1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: range + Values: [1000.01 0.02 10000.03] + Comment: float64Range1 + UpdateMode: dynamic + */ + float64Range1 float64 + + //parameter name -> parameter definition string + name2definition map[string]string +} //end AllParameters + +//all parameters can be set in the configuration file. +type configuration struct { + //read and write lock + rwlock sync.RWMutex + + /** + Name: boolSet1 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [true] + Comment: boolSet1 + UpdateMode: dynamic + */ + BoolSet1 bool `toml:"boolSet1"` + + /** + Name: boolSet2 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [false] + Comment: boolSet2 + UpdateMode: hotload + */ + BoolSet2 bool `toml:"boolSet2"` + + /** + Name: boolSet3 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [] + Comment: boolSet3 + UpdateMode: dynamic + */ + BoolSet3 bool `toml:"boolSet3"` + + /** + Name: stringSet1 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [ss1 ss2 ss3] + Comment: stringSet1 + UpdateMode: dynamic + */ + StringSet1 string `toml:"stringSet1"` + + /** + Name: stringSet2 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [] + Comment: stringSet2 + UpdateMode: dynamic + */ + StringSet2 string `toml:"stringSet2"` + + /** + Name: int64set1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [1 2 3 4 5 6] + Comment: int64Set1 + UpdateMode: dynamic + */ + Int64set1 int64 `toml:"int64set1"` + + /** + Name: int64set3 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [] + Comment: int64Set3 + UpdateMode: dynamic + */ + Int64set3 int64 `toml:"int64set3"` + + /** + Name: int64Range1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: range + Values: [1000 0 10000] + Comment: int64Range1 + UpdateMode: dynamic + */ + Int64Range1 int64 `toml:"int64Range1"` + + /** + Name: float64set1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [1.0 2.0 3.0 4.00 5.0 6.0] + Comment: float64Set1 + UpdateMode: dynamic + */ + Float64set1 float64 `toml:"float64set1"` + + /** + Name: float64set3 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [] + Comment: float64Set3 + UpdateMode: dynamic + */ + Float64set3 float64 `toml:"float64set3"` + + /** + Name: float64Range1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: range + Values: [1000.01 0.02 10000.03] + Comment: float64Range1 + UpdateMode: dynamic + */ + Float64Range1 float64 `toml:"float64Range1"` + + //parameter name -> updated flag + name2updatedFlags map[string]bool +} //end configuration + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (ap *AllParameters) prepareAnything() { + if ap.name2definition == nil { + ap.name2definition = make(map[string]string) + } +} + +/** +set parameter and its string of the definition. +*/ +func (ap *AllParameters) PrepareDefinition() { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + ap.prepareAnything() + + ap.name2definition["boolSet1"] = " Name: boolSet1 Scope: [global] Access: [file] DataType: bool DomainType: set Values: [true] Comment: boolSet1 UpdateMode: dynamic " + + ap.name2definition["boolSet2"] = " Name: boolSet2 Scope: [global] Access: [file] DataType: bool DomainType: set Values: [false] Comment: boolSet2 UpdateMode: hotload " + + ap.name2definition["boolSet3"] = " Name: boolSet3 Scope: [global] Access: [file] DataType: bool DomainType: set Values: [] Comment: boolSet3 UpdateMode: dynamic " + + ap.name2definition["stringSet1"] = " Name: stringSet1 Scope: [global] Access: [file] DataType: string DomainType: set Values: [ss1 ss2 ss3] Comment: stringSet1 UpdateMode: dynamic " + + ap.name2definition["stringSet2"] = " Name: stringSet2 Scope: [global] Access: [file] DataType: string DomainType: set Values: [] Comment: stringSet2 UpdateMode: dynamic " + + ap.name2definition["int64set1"] = " Name: int64set1 Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [1 2 3 4 5 6] Comment: int64Set1 UpdateMode: dynamic " + + ap.name2definition["int64set2"] = " Name: int64set2 Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [1 3 5 7] Comment: int64Set2 UpdateMode: fix " + + ap.name2definition["int64set3"] = " Name: int64set3 Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [] Comment: int64Set3 UpdateMode: dynamic " + + ap.name2definition["int64Range1"] = " Name: int64Range1 Scope: [global] Access: [file] DataType: int64 DomainType: range Values: [1000 0 10000] Comment: int64Range1 UpdateMode: dynamic " + + ap.name2definition["float64set1"] = " Name: float64set1 Scope: [global] Access: [file] DataType: float64 DomainType: set Values: [1.0 2.0 3.0 4.00 5.0 6.0] Comment: float64Set1 UpdateMode: dynamic " + + ap.name2definition["float64set2"] = " Name: float64set2 Scope: [global] Access: [file] DataType: float64 DomainType: set Values: [1.001 3.003 5.005 7.007] Comment: float64Set2 UpdateMode: fix " + + ap.name2definition["float64set3"] = " Name: float64set3 Scope: [global] Access: [file] DataType: float64 DomainType: set Values: [] Comment: float64Set3 UpdateMode: dynamic " + + ap.name2definition["float64Range1"] = " Name: float64Range1 Scope: [global] Access: [file] DataType: float64 DomainType: range Values: [1000.01 0.02 10000.03] Comment: float64Range1 UpdateMode: dynamic " + +} + +/** +get the definition of the parameter. +*/ +func (ap *AllParameters) GetDefinition(name string) (string, error) { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if p, ok := ap.name2definition[name]; !ok { + return "", fmt.Errorf("there is no parameter %s", name) + } else { + return p, nil + } +} + +/** +check if there is the parameter +*/ +func (ap *AllParameters) HasParameter(name string) bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if _, ok := ap.name2definition[name]; !ok { + return false + } else { + return true + } +} + +/** +Load the initial values of all parameters. +*/ +func (ap *AllParameters) LoadInitialValues() error { + ap.PrepareDefinition() + var err error + + boolSet1choices := []bool{ + + true, + } + if len(boolSet1choices) != 0 { + if err = ap.setBoolSet1(boolSet1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet1", err) + } + } else { + + if err = ap.setBoolSet1(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet1", err) + } + + } + + boolSet2choices := []bool{ + + false, + } + if len(boolSet2choices) != 0 { + if err = ap.setBoolSet2(boolSet2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet2", err) + } + } else { + + if err = ap.setBoolSet2(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet2", err) + } + + } + + boolSet3choices := []bool{} + if len(boolSet3choices) != 0 { + if err = ap.setBoolSet3(boolSet3choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet3", err) + } + } else { + + if err = ap.setBoolSet3(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet3", err) + } + + } + + stringSet1choices := []string{ + + "ss1", + + "ss2", + + "ss3", + } + if len(stringSet1choices) != 0 { + if err = ap.setStringSet1(stringSet1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet1", err) + } + } else { + //empty string + if err = ap.setStringSet1(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet1", err) + } + } + + stringSet2choices := []string{} + if len(stringSet2choices) != 0 { + if err = ap.setStringSet2(stringSet2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet2", err) + } + } else { + //empty string + if err = ap.setStringSet2(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet2", err) + } + } + + int64set1choices := []int64{ + + 1, + + 2, + + 3, + + 4, + + 5, + + 6, + } + if len(int64set1choices) != 0 { + if err = ap.setInt64set1(int64set1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set1", err) + } + } else { + + if err = ap.setInt64set1(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set1", err) + } + + } + + int64set2choices := []int64{ + + 1, + + 3, + + 5, + + 7, + } + if len(int64set2choices) != 0 { + if err = ap.setInt64set2(int64set2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set2", err) + } + } else { + + if err = ap.setInt64set2(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set2", err) + } + + } + + int64set3choices := []int64{} + if len(int64set3choices) != 0 { + if err = ap.setInt64set3(int64set3choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set3", err) + } + } else { + + if err = ap.setInt64set3(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set3", err) + } + + } + + int64Range1choices := []int64{ + + 1000, + + 0, + + 10000, + } + if len(int64Range1choices) != 0 { + if err = ap.setInt64Range1(int64Range1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64Range1", err) + } + } else { + + if err = ap.setInt64Range1(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64Range1", err) + } + + } + + float64set1choices := []float64{ + + 1.0, + + 2.0, + + 3.0, + + 4.00, + + 5.0, + + 6.0, + } + if len(float64set1choices) != 0 { + if err = ap.setFloat64set1(float64set1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set1", err) + } + } else { + + if err = ap.setFloat64set1(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set1", err) + } + + } + + float64set2choices := []float64{ + + 1.001, + + 3.003, + + 5.005, + + 7.007, + } + if len(float64set2choices) != 0 { + if err = ap.setFloat64set2(float64set2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set2", err) + } + } else { + + if err = ap.setFloat64set2(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set2", err) + } + + } + + float64set3choices := []float64{} + if len(float64set3choices) != 0 { + if err = ap.setFloat64set3(float64set3choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set3", err) + } + } else { + + if err = ap.setFloat64set3(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set3", err) + } + + } + + float64Range1choices := []float64{ + + 1000.01, + + 0.02, + + 10000.03, + } + if len(float64Range1choices) != 0 { + if err = ap.setFloat64Range1(float64Range1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64Range1", err) + } + } else { + + if err = ap.setFloat64Range1(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64Range1", err) + } + + } + + return nil +} + +/** +Get the value of the parameter boolSet1 +*/ +func (ap *AllParameters) GetBoolSet1() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.boolSet1 +} + +/** +Get the value of the parameter boolSet2 +*/ +func (ap *AllParameters) GetBoolSet2() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.boolSet2 +} + +/** +Get the value of the parameter boolSet3 +*/ +func (ap *AllParameters) GetBoolSet3() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.boolSet3 +} + +/** +Get the value of the parameter stringSet1 +*/ +func (ap *AllParameters) GetStringSet1() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.stringSet1 +} + +/** +Get the value of the parameter stringSet2 +*/ +func (ap *AllParameters) GetStringSet2() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.stringSet2 +} + +/** +Get the value of the parameter int64set1 +*/ +func (ap *AllParameters) GetInt64set1() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64set1 +} + +/** +Get the value of the parameter int64set2 +*/ +func (ap *AllParameters) GetInt64set2() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64set2 +} + +/** +Get the value of the parameter int64set3 +*/ +func (ap *AllParameters) GetInt64set3() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64set3 +} + +/** +Get the value of the parameter int64Range1 +*/ +func (ap *AllParameters) GetInt64Range1() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64Range1 +} + +/** +Get the value of the parameter float64set1 +*/ +func (ap *AllParameters) GetFloat64set1() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64set1 +} + +/** +Get the value of the parameter float64set2 +*/ +func (ap *AllParameters) GetFloat64set2() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64set2 +} + +/** +Get the value of the parameter float64set3 +*/ +func (ap *AllParameters) GetFloat64set3() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64set3 +} + +/** +Get the value of the parameter float64Range1 +*/ +func (ap *AllParameters) GetFloat64Range1() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64Range1 +} + +/** +Set the value of the parameter boolSet1 +*/ +func (ap *AllParameters) SetBoolSet1(value bool) error { + return ap.setBoolSet1(value) +} + +/** +Set the value of the parameter boolSet2 +*/ +func (ap *AllParameters) SetBoolSet2(value bool) error { + return ap.setBoolSet2(value) +} + +/** +Set the value of the parameter boolSet3 +*/ +func (ap *AllParameters) SetBoolSet3(value bool) error { + return ap.setBoolSet3(value) +} + +/** +Set the value of the parameter stringSet1 +*/ +func (ap *AllParameters) SetStringSet1(value string) error { + return ap.setStringSet1(value) +} + +/** +Set the value of the parameter stringSet2 +*/ +func (ap *AllParameters) SetStringSet2(value string) error { + return ap.setStringSet2(value) +} + +/** +Set the value of the parameter int64set1 +*/ +func (ap *AllParameters) SetInt64set1(value int64) error { + return ap.setInt64set1(value) +} + +/** +Set the value of the parameter int64set3 +*/ +func (ap *AllParameters) SetInt64set3(value int64) error { + return ap.setInt64set3(value) +} + +/** +Set the value of the parameter int64Range1 +*/ +func (ap *AllParameters) SetInt64Range1(value int64) error { + return ap.setInt64Range1(value) +} + +/** +Set the value of the parameter float64set1 +*/ +func (ap *AllParameters) SetFloat64set1(value float64) error { + return ap.setFloat64set1(value) +} + +/** +Set the value of the parameter float64set3 +*/ +func (ap *AllParameters) SetFloat64set3(value float64) error { + return ap.setFloat64set3(value) +} + +/** +Set the value of the parameter float64Range1 +*/ +func (ap *AllParameters) SetFloat64Range1(value float64) error { + return ap.setFloat64Range1(value) +} + +/** +Set the value of the parameter boolSet1 +*/ +func (ap *AllParameters) setBoolSet1(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{ + + true, + } + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setBoolSet1,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.boolSet1 = value + return nil +} + +/** +Set the value of the parameter boolSet2 +*/ +func (ap *AllParameters) setBoolSet2(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{ + + false, + } + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setBoolSet2,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.boolSet2 = value + return nil +} + +/** +Set the value of the parameter boolSet3 +*/ +func (ap *AllParameters) setBoolSet3(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{} + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setBoolSet3,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.boolSet3 = value + return nil +} + +/** +Set the value of the parameter stringSet1 +*/ +func (ap *AllParameters) setStringSet1(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "ss1", + + "ss2", + + "ss3", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setStringSet1,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.stringSet1 = value + return nil +} + +/** +Set the value of the parameter stringSet2 +*/ +func (ap *AllParameters) setStringSet2(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{} + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setStringSet2,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.stringSet2 = value + return nil +} + +/** +Set the value of the parameter int64set1 +*/ +func (ap *AllParameters) setInt64set1(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 1, + + 2, + + 3, + + 4, + + 5, + + 6, + } + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setInt64set1,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.int64set1 = value + return nil +} + +/** +Set the value of the parameter int64set2 +*/ +func (ap *AllParameters) setInt64set2(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 1, + + 3, + + 5, + + 7, + } + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setInt64set2,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.int64set2 = value + return nil +} + +/** +Set the value of the parameter int64set3 +*/ +func (ap *AllParameters) setInt64set3(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{} + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setInt64set3,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.int64set3 = value + return nil +} + +/** +Set the value of the parameter int64Range1 +*/ +func (ap *AllParameters) setInt64Range1(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 1000, + + 0, + + 10000, + } + if !(value >= choices[1] && value <= choices[2]) { + return fmt.Errorf("setInt64Range1,the value %d is not in the range [%d,%d]", value, choices[1], choices[2]) + } + + ap.int64Range1 = value + return nil +} + +/** +Set the value of the parameter float64set1 +*/ +func (ap *AllParameters) setFloat64set1(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{ + + 1.0, + + 2.0, + + 3.0, + + 4.00, + + 5.0, + + 6.0, + } + if len(choices) != 0 { + if !isInSliceFloat64(value, choices) { + return fmt.Errorf("setFloat64set1,the value %f is not in set %v", value, choices) + } + } //else means any float64 + + ap.float64set1 = value + return nil +} + +/** +Set the value of the parameter float64set2 +*/ +func (ap *AllParameters) setFloat64set2(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{ + + 1.001, + + 3.003, + + 5.005, + + 7.007, + } + if len(choices) != 0 { + if !isInSliceFloat64(value, choices) { + return fmt.Errorf("setFloat64set2,the value %f is not in set %v", value, choices) + } + } //else means any float64 + + ap.float64set2 = value + return nil +} + +/** +Set the value of the parameter float64set3 +*/ +func (ap *AllParameters) setFloat64set3(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{} + if len(choices) != 0 { + if !isInSliceFloat64(value, choices) { + return fmt.Errorf("setFloat64set3,the value %f is not in set %v", value, choices) + } + } //else means any float64 + + ap.float64set3 = value + return nil +} + +/** +Set the value of the parameter float64Range1 +*/ +func (ap *AllParameters) setFloat64Range1(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{ + + 1000.01, + + 0.02, + + 10000.03, + } + if !(value >= choices[1] && value <= choices[2]) { + return fmt.Errorf("setFloat64Range1,the value %f is not in the range [%f,%f]", value, choices[1], choices[2]) + } + + ap.float64Range1 = value + return nil +} + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (config *configuration) prepareAnything() { + if config.name2updatedFlags == nil { + config.name2updatedFlags = make(map[string]bool) + } +} + +/** +reset update flags of configuration items +*/ +func (config *configuration) resetUpdatedFlags() { + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + + config.name2updatedFlags["boolSet1"] = false + + config.name2updatedFlags["boolSet2"] = false + + config.name2updatedFlags["boolSet3"] = false + + config.name2updatedFlags["stringSet1"] = false + + config.name2updatedFlags["stringSet2"] = false + + config.name2updatedFlags["int64set1"] = false + + config.name2updatedFlags["int64set3"] = false + + config.name2updatedFlags["int64Range1"] = false + + config.name2updatedFlags["float64set1"] = false + + config.name2updatedFlags["float64set3"] = false + + config.name2updatedFlags["float64Range1"] = false + +} + +/** +set update flag of configuration item +*/ +func (config *configuration) setUpdatedFlag(name string, updated bool) { + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + config.name2updatedFlags[name] = updated +} + +/** +get update flag of configuration item +*/ +func (config *configuration) getUpdatedFlag(name string) bool { + config.rwlock.RLock() + defer config.rwlock.RUnlock() + config.prepareAnything() + return config.name2updatedFlags[name] +} + +/** +Load parameters' values in the configuration string. +*/ +func (config *configuration) LoadConfigurationFromString(input string) error { + config.resetUpdatedFlags() + + metadata, err := toml.Decode(input, config) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + for _, k := range metadata.Keys() { + config.setUpdatedFlag(k[0], true) + } + + return nil +} + +/** +Load parameters' values in the configuration file. +*/ +func (config *configuration) LoadConfigurationFromFile(fname string) error { + config.resetUpdatedFlags() + + metadata, err := toml.DecodeFile(fname, config) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + for _, k := range metadata.Keys() { + config.setUpdatedFlag(k[0], true) + } + + return nil +} + +/** +Update parameters' values with configuration. +*/ +func (ap *AllParameters) UpdateParametersWithConfiguration(config *configuration) error { + var err error + + if config.getUpdatedFlag("boolSet1") { + if err = ap.setBoolSet1(config.BoolSet1); err != nil { + return fmt.Errorf("update parameter boolSet1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("boolSet2") { + if err = ap.setBoolSet2(config.BoolSet2); err != nil { + return fmt.Errorf("update parameter boolSet2 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("boolSet3") { + if err = ap.setBoolSet3(config.BoolSet3); err != nil { + return fmt.Errorf("update parameter boolSet3 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("stringSet1") { + if err = ap.setStringSet1(config.StringSet1); err != nil { + return fmt.Errorf("update parameter stringSet1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("stringSet2") { + if err = ap.setStringSet2(config.StringSet2); err != nil { + return fmt.Errorf("update parameter stringSet2 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("int64set1") { + if err = ap.setInt64set1(config.Int64set1); err != nil { + return fmt.Errorf("update parameter int64set1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("int64set3") { + if err = ap.setInt64set3(config.Int64set3); err != nil { + return fmt.Errorf("update parameter int64set3 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("int64Range1") { + if err = ap.setInt64Range1(config.Int64Range1); err != nil { + return fmt.Errorf("update parameter int64Range1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("float64set1") { + if err = ap.setFloat64set1(config.Float64set1); err != nil { + return fmt.Errorf("update parameter float64set1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("float64set3") { + if err = ap.setFloat64set3(config.Float64set3); err != nil { + return fmt.Errorf("update parameter float64set3 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("float64Range1") { + if err = ap.setFloat64Range1(config.Float64Range1); err != nil { + return fmt.Errorf("update parameter float64Range1 failed.error:%v", err) + } + } + + return nil +} diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go new file mode 100644 index 0000000000000000000000000000000000000000..090c2599ddc5c3406ec288247dca84ee99f0ae08 --- /dev/null +++ b/pkg/config/parameters_test.go @@ -0,0 +1,159 @@ +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "sync" + "testing" +) + +func TestAllParameters_LoadInitialValues(t *testing.T) { + ap := &AllParameters{} + if err := ap.LoadInitialValues(); err != nil { + t.Errorf("LoadInitialValues failed. error:%v", err) + } +} + +func isconfigurationEqual(c1, c2 configuration) bool { + + if c1.BoolSet1 != c2.BoolSet1 { + return false + } + + if c1.BoolSet2 != c2.BoolSet2 { + return false + } + + if c1.BoolSet3 != c2.BoolSet3 { + return false + } + + if c1.StringSet1 != c2.StringSet1 { + return false + } + + if c1.StringSet2 != c2.StringSet2 { + return false + } + + if c1.Int64set1 != c2.Int64set1 { + return false + } + + if c1.Int64set3 != c2.Int64set3 { + return false + } + + if c1.Int64Range1 != c2.Int64Range1 { + return false + } + + if c1.Float64set1 != c2.Float64set1 { + return false + } + + if c1.Float64set3 != c2.Float64set3 { + return false + } + + if c1.Float64Range1 != c2.Float64Range1 { + return false + } + + return true +} + +func Test_configuration_LoadConfigurationFromString(t *testing.T) { + t1 := ` + +boolSet1=true + +boolSet2=false + +boolSet3= false + +stringSet1= "ss1" + +stringSet2= "" + +int64set1=1 + + + +int64set3= 0 + +int64Range1=1000 + +float64set1=1.0 + + + +float64set3= 0.0 + +float64Range1=1000.01 + +` + t1_config := configuration{ + rwlock: sync.RWMutex{}, + + BoolSet1: true, + + BoolSet2: false, + + BoolSet3: false, + + StringSet1: "ss1", + + StringSet2: "", + + Int64set1: 1, + + Int64set3: 0, + + Int64Range1: 1000, + + Float64set1: 1.0, + + Float64set3: 0.0, + + Float64Range1: 1000.01, + + name2updatedFlags: nil, + } + + type args struct { + input string + config configuration + } + tests := []struct { + name string + args args + wantErr bool + wantErr2 bool + wantErr3 bool + }{ + {"t1", args{t1, t1_config}, false, false, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ap := &AllParameters{} + if err := ap.LoadInitialValues(); err != nil { + t.Errorf("LoadInitialValues failed.error %v", err) + } + config := &configuration{} + if err := config.LoadConfigurationFromString(tt.args.input); (err != nil) != tt.wantErr { + t.Errorf("LoadConfigurationFromString() error = %v, wantErr %v", err, tt.wantErr) + } else if err != nil { + return + } + + if err := ap.UpdateParametersWithConfiguration(config); (err != nil) != tt.wantErr2 { + t.Errorf("UpdateParametersWithConfiguration failed. error:%v", err) + } + + if (isconfigurationEqual(*config, tt.args.config) != true) != tt.wantErr3 { + t.Errorf("Configuration are not equal. %v vs %v ", *config, tt.args.config) + return + } + }) + } +} diff --git a/pkg/config/test/config.toml b/pkg/config/test/config.toml new file mode 100644 index 0000000000000000000000000000000000000000..e79411e031253506282f7a448e310beca5ae5e59 --- /dev/null +++ b/pkg/config/test/config.toml @@ -0,0 +1,139 @@ + +# Code generated by tool; DO NOT EDIT. + + + +# Name: boolSet1 +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [true] +# Comment: boolSet1 +# UpdateMode: dynamic + boolSet1=true + + + +# Name: boolSet2 +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [false] +# Comment: boolSet2 +# UpdateMode: hotload + boolSet2=false + + + +# Name: boolSet3 +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [] +# Comment: boolSet3 +# UpdateMode: dynamic + boolSet3= false + + + +# Name: stringSet1 +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [ss1 ss2 ss3] +# Comment: stringSet1 +# UpdateMode: dynamic + stringSet1= "ss1" + + + +# Name: stringSet2 +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [] +# Comment: stringSet2 +# UpdateMode: dynamic + stringSet2= "" + + + +# Name: int64set1 +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: set +# Values: [1 2 3 4 5 6] +# Comment: int64Set1 +# UpdateMode: dynamic + int64set1=1 + + + + + +# Name: int64set3 +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: set +# Values: [] +# Comment: int64Set3 +# UpdateMode: dynamic + int64set3= 0 + + + +# Name: int64Range1 +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: range +# Values: [1000 0 10000] +# Comment: int64Range1 +# UpdateMode: dynamic + int64Range1=1000 + + + +# Name: float64set1 +# Scope: [global] +# Access: [file] +# DataType: float64 +# DomainType: set +# Values: [1.0 2.0 3.0 4.00 5.0 6.0] +# Comment: float64Set1 +# UpdateMode: dynamic + float64set1=1.0 + + + + + +# Name: float64set3 +# Scope: [global] +# Access: [file] +# DataType: float64 +# DomainType: set +# Values: [] +# Comment: float64Set3 +# UpdateMode: dynamic + float64set3= 0.0 + + + +# Name: float64Range1 +# Scope: [global] +# Access: [file] +# DataType: float64 +# DomainType: range +# Values: [1000.01 0.02 10000.03] +# Comment: float64Range1 +# UpdateMode: dynamic + float64Range1=1000.01 + diff --git a/pkg/config/test/config_template.go b/pkg/config/test/config_template.go new file mode 100644 index 0000000000000000000000000000000000000000..3f1d76d6adeb34785bca9ce6e38bacf0ea098504 --- /dev/null +++ b/pkg/config/test/config_template.go @@ -0,0 +1,1366 @@ +package config + +import ( + "fmt" + "github.com/BurntSushi/toml" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "text/template" + "unicode" +) + +/* + scope options: + + session: + + If you change a session parameter, + the value remains in effect within your session until you change the variable to a different value + or the session ends. + The change has no effect on other sessions. + + global: + + If you change a global parameter, the value is remembered and used to initialize the session value + for new sessions until you change the parameter to a different value or the server exits. + The change is visible to any client that accesses the global value. + However, the change affects the corresponding session value only for clients that connect after the change. + The global parameter change does not affect the session value for any current client sessions ( + not even the session within which the global value change occurs). +*/ +var scopeOptions = []string{"session", "global"} + +//the access +var accessOptions = []string{"cmd", "file", "env"} + +//the data type +var dataTypeOptions = []string{"string", "int64", "float64", "bool"} + +var boolFalseOptions = []string{"false", "off"} +var boolTrueOptions = []string{"true", "on"} + +//the domain +var domainTyoeOptions = []string{"set", "range"} + +//the updateMode +var updateModeOptions = []string{"dynamic", "fix", "hotload"} + +//a unit in configuration template for a configuration item +type parameter struct { + //the Name + Name string `toml:"name"` + + //also the Name whose initial character is capital + CapitalName string + + //the scope (also visibility) + //where can the others see the value + Scope []string `toml:"scope"` + + //the access: command line; configure file; environment variable in the shell + //where the value can be changed + Access []string `toml:"access"` + + //the data type of the value like int, string ,bool,float,... + DataType string `toml:"type"` + + //the domain of the value for validity: set; range; + //set: select one among discrete values. + //range: select a point in a real range + DomainType string `toml:"domain-type"` + + /** + The first one is the initial-value. + for range domain-type + [initial-value,minimum,maximum] + + for set domain-type + normal situation + [initial-value,value2,value3,value4,...,] + + special situation + [] is empty, you can set any value in the domain of the data type + */ + Values []string `toml:"values"` + + //the comment + Comment string `toml:"comment"` + + //the update mode in running + //dynamic: can be updated in running + //fix: can not be updated in running + //hotLoad: can be loaded from the config file and updated in running + UpdateMode string `toml:"update-mode"` +} + +type parameters struct { + //the name of parameter data structure + //the parameter structure can be exported. + //the first character must be capital. + ParameterStructName string `toml:"parameter-struct-name"` + + //the name of configuration data structure + //the configuration structure is an internal structure that will not be exported. + //the first character should not be capital. + ConfigurationStructName string `toml:"config-struct-name"` + + //the name of operation file which contains all interface code for operating parameters + //without ".go" + OperationFileName string `toml:"operation-file-name"` + + //the name of configuration file which contains all auto generated parameters. + //without ".toml" + ConfigurationFileName string `toml:"config-file-name"` + + //the array of parameters + Parameter []parameter +} + +/** +load and analyse parameters definition from the template file +*/ +func (params *parameters) LoadParametersDefinitionFromFile(filename string) error { + pfile, err := os.Open(filename) + if err != nil { + return err + } + defer pfile.Close() + + fbytes, err := ioutil.ReadAll(pfile) + if err != nil { + return err + } + return params.LoadParametersDefinitionFromString(string(fbytes)) +} + +func (params *parameters) LoadParametersDefinitionFromString(input string) error { + metadata, err := toml.Decode(input, params) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + //check parameter-struct-name + if !isExportedGoIdentifier(params.ParameterStructName) { + return fmt.Errorf("ParameterStructName [%s] is not a valid identifier name within ascii characters", params.ParameterStructName) + } + + //check config-struct-name + if !isGoIdentifier(params.ConfigurationStructName) { + return fmt.Errorf("ConfigurationStructName [%s] is not a valid identifier name within ascii characters", params.ConfigurationStructName) + } + + //check parameter operation file name + if !isGoStructAndInterfaceIdentifier(params.OperationFileName) { + return fmt.Errorf("OperationFileName [%s] is not a valid identifier name within ascii characters", params.OperationFileName) + } + + //check parameter configuration file name + if !isGoStructAndInterfaceIdentifier(params.ConfigurationFileName) { + return fmt.Errorf("ConfigurationFileName [%s] is not a valid identifier name within ascii characters", params.ConfigurationFileName) + } + + //check parameter + for _, p := range params.Parameter { + if !isGoIdentifier(p.Name) { + return fmt.Errorf("Name [%s] is not a valid identifier name within ascii characters", p.Name) + } + + if !isScope(p.Scope) { + return fmt.Errorf("Scope [%s] is not a valid scope", p.Scope) + } + + if !isAccess(p.Access) { + return fmt.Errorf("Access [%s] is not a valid access", p.Access) + } + + if !isDataType(p.DataType) { + return fmt.Errorf("DataType [%s] is not a valid data type", p.DataType) + } + + if !isDomainType(p.DomainType) { + return fmt.Errorf("DomainType [%s] is not a valid domain type", p.DomainType) + } + + if !checkValues(p.DataType, p.DomainType, p.Values) { + return fmt.Errorf("Values [%s] is not compatible with data type %s and domain type %s", p.Values, p.DataType, p.DomainType) + } + + if !isUpdateMode(p.UpdateMode) { + return fmt.Errorf("UpdateMode [%s] is not a valid update mode", p.UpdateMode) + } + } + + //parameter name dedup + var dedup = make(map[string]bool) + + if _, ok := dedup[params.ParameterStructName]; !ok { + dedup[params.ParameterStructName] = true + } else { + return fmt.Errorf("has duplicate parameter struct name %s.", params.ParameterStructName) + } + + if _, ok := dedup[params.ConfigurationStructName]; !ok { + dedup[params.ConfigurationStructName] = true + } else { + return fmt.Errorf("has duplicate configuration struct name %s.", params.ConfigurationStructName) + } + + if _, ok := dedup[params.OperationFileName]; !ok { + dedup[params.OperationFileName] = true + } else { + return fmt.Errorf("has duplicate operation file name %s.", params.OperationFileName) + } + + if _, ok := dedup[params.ConfigurationFileName]; !ok { + dedup[params.ConfigurationFileName] = true + } else { + return fmt.Errorf("has duplicate configuration file name %s.", params.ConfigurationFileName) + } + + for _, p := range params.Parameter { + if _, ok := dedup[p.Name]; !ok { + dedup[p.Name] = true + } else { + return fmt.Errorf("has duplicate parameter name %s.", p.Name) + } + } + + //make capital name for the name + for i := 0; i < len(params.Parameter); i++ { + p := params.Parameter[i].Name + capName := p + capName = string(unicode.ToUpper(rune(p[0]))) + p[1:] + params.Parameter[i].CapitalName = capName + } + + return err +} + +/** +check the x is a valid low case ascii character +*/ +func isLowCaseAsciiChar(x byte) bool { + return x >= 'a' && x <= 'z' || x == '_' +} + +/** +check the x is a valid low case ascii character +*/ +func isUpCaseAsciiChar(x byte) bool { + return x >= 'A' && x <= 'Z' +} + +/** +check the x is a valid ascii character +*/ +func isAsciiChar(x byte) bool { + return x >= 'a' && x <= 'z' || x >= 'A' && x <= 'Z' || x == '_' +} + +/** +check the x is a valid ascii digit +*/ +func isAsciiDigit(x byte) bool { + return x >= '0' && x <= '9' +} + +/** +check if the string can be a valid identifier in Golang. + +In our context, the identifier can be defined as follow: +identifier = low-case-letter { letter | digit } +low-case-letter = "a" ... "z" | "_" +letter = "a" ... "z" | "A" ... "Z" | "_" +digit = "0" ... "9" + +here,the letter just has the ascii characters. +So,it's the subset of the identifier in Golang. +*/ +func isGoIdentifier(s string) bool { + if len(s) == 0 { + return false + } + + //the first character is a low case ascii character. + if !isLowCaseAsciiChar(s[0]) { + return false + } + + //the rest should ascii character | ascii digit | _ + for i := 1; i < len(s); i++ { + if !(isAsciiChar(s[i]) || isAsciiDigit(s[i])) { + return false + } + } + + return true +} + +/** +check if the string can be a valid identifier in Golang. + +In our context, the identifier can be defined as follow: +identifier = up-case-letter { letter | digit } +up-case-letter = "A" ... "Z" +letter = "a" ... "z" | "A" ... "Z" | "_" +digit = "0" ... "9" + +here,the letter just has the ascii characters. +So,it's the subset of the identifier in Golang. +*/ +func isExportedGoIdentifier(s string) bool { + if len(s) == 0 { + return false + } + + //the first character is a low case ascii character. + if !isUpCaseAsciiChar(s[0]) { + return false + } + + //the rest should ascii character | ascii digit | _ + for i := 1; i < len(s); i++ { + if !(isAsciiChar(s[i]) || isAsciiDigit(s[i])) { + return false + } + } + + return true +} + +/** +check if the string can be a valid struct and interface identifier in Golang. + +In our context, the identifier can be defined as follow: +identifier = letter { letter | digit } +letter = "a" ... "z" | "A" ... "Z" | "_" +digit = "0" ... "9" + +here,the letter just has the ascii characters. +So,it's the subset of the identifier in Golang. +*/ +func isGoStructAndInterfaceIdentifier(s string) bool { + if len(s) == 0 { + return false + } + + //the first character is a low case ascii character. + if !isAsciiChar(s[0]) { + return false + } + + //the rest should ascii character | ascii digit | _ + for i := 1; i < len(s); i++ { + if !(isAsciiChar(s[i]) || isAsciiDigit(s[i])) { + return false + } + } + + return true +} + +/** +check if the scope is valid. +*/ +func isScope(sc []string) bool { + return isSubset(sc, scopeOptions) +} + +/** +check if the access is valid. +*/ +func isAccess(sc []string) bool { + return isSubset(sc, accessOptions) +} + +/** +check if the data type is valid +*/ +func isDataType(x string) bool { + return isInSlice(x, dataTypeOptions) +} + +/** +check if the domain type is valid +*/ +func isDomainType(x string) bool { + return isInSlice(x, domainTyoeOptions) +} + +/** +make a float string look like a float64 string. +*/ +func looklikeFloat64String(s string) string { + if i := strings.Index(s, "."); i != -1 { + if i == len(s)-1 { //. is the last one, append a zero + return s + "0" + } + return s + } else { + return s + ".0" + } +} + +/** +check if the values are valid based on dataType, domainType. +*/ +func checkValues(dataType string, domainType string, values []string) bool { + switch dataType { + case "string": + switch domainType { + case "set": + if len(values) < 1 { + return true + } else if len(values) == 1 { + return true + } else { + if hasDuplicateValueString(values) { + return false + } + } + return true + case "range": + return false + default: + return false + } + case "int64": + switch domainType { + case "set": + if len(values) < 1 { + return true + } + + var intArr []int64 + for i := 0; i < len(values); i++ { + if v, err := strconv.ParseInt(values[i], 10, 64); err != nil { + return false + } else { + intArr = append(intArr, v) + } + } + + if len(intArr) == 1 { + return true + } + + //first one is the default value. + //there are no duplicate values in the set. + if hasDuplicateValueInt64(intArr) { + return false + } + return true + case "range": + if len(values) != 3 { + return false + } + + var intArr []int64 + for i := 0; i < len(values); i++ { + if v, err := strconv.ParseInt(values[i], 10, 64); err != nil { + return false + } else { + intArr = append(intArr, v) + } + } + + if !(intArr[0] >= intArr[1] && intArr[0] <= intArr[2]) { + return false + } + return true + } + case "float64": + switch domainType { + case "set": + if len(values) < 1 { + return true + } + + var fArr []float64 + for i := 0; i < len(values); i++ { + if v, err := strconv.ParseFloat(values[i], 64); err != nil { + return false + } else { + fArr = append(fArr, v) + } + } + + if len(fArr) == 1 { + return true + } + + if hasDuplicateValueFloat64(fArr) { + return false + } + + //for configuration file generation + for i := 0; i < len(values); i++ { + values[i] = looklikeFloat64String(values[i]) + } + + return true + case "range": + if len(values) != 3 { + return false + } + + var fArr []float64 + for i := 0; i < len(values); i++ { + if v, err := strconv.ParseFloat(values[i], 64); err != nil { + return false + } else { + fArr = append(fArr, v) + } + } + + if !(fArr[0] >= fArr[1] && fArr[0] <= fArr[2]) { + return false + } + return true + } + case "bool": + switch domainType { + case "set": + if len(values) < 1 { + return true + } + + if len(values) != 1 { + return false + } + + low := strings.ToLower(values[0]) + if !isInSlice(low, boolFalseOptions) && !isInSlice(low, boolTrueOptions) { + return false + } + return true + case "range": + return false + default: + + } + } + + return false +} + +/** +check if the update mode is valid +*/ +func isUpdateMode(um string) bool { + return isInSlice(um, updateModeOptions) +} + +/** +check if A is a valid subset of B. +if A has something that is not in B,then return false. +if A has duplicate elements,then return false. +if A has nothing,then return false. +*/ +func isSubset(A []string, B []string) bool { + if len(A) > len(B) { + return false + } + + sort.Strings(B) + + //check the element of A is in B or not + for _, x := range A { + if !isInSlice(x, B) { + return false + } + } + + //check the A has duplicate elements + dedup := map[string]bool{} + for _, x := range A { + if _, ok := dedup[x]; ok { //duplicate scope + return false + } + dedup[x] = true + } + + return len(A) > 0 +} + +/** +check if x in a slice +*/ +func isInSlice(x string, arr []string) bool { + for _, y := range arr { + if x == y { + return true + } + } + return false +} + +/** +check if x in a slice +*/ +func isInSliceBool(x bool, arr []bool) bool { + for _, y := range arr { + if x == y { + return true + } + } + return false +} + +/** +check if x in a slice +*/ +func isInSliceInt64(x int64, arr []int64) bool { + for _, y := range arr { + if x == y { + return true + } + } + return false +} + +/** +check if x in a slice +*/ +func isInSliceFloat64(x float64, arr []float64) bool { + for _, y := range arr { + if x == y { + return true + } + } + return false +} + +/** +check if x has duplicate values. +*/ +func hasDuplicateValueString(x []string) bool { + var dedup = make(map[string]bool) + for _, v := range x { + if _, ok := dedup[v]; !ok { + dedup[v] = true + } else { + return true + } + } + return false +} + +/** +check if x has duplicate values. +*/ +func hasDuplicateValueInt64(x []int64) bool { + var dedup = make(map[int64]bool) + for _, v := range x { + if _, ok := dedup[v]; !ok { + dedup[v] = true + } else { + return true + } + } + return false +} + +/** +check if x has duplicate values. +*/ +func hasDuplicateValueFloat64(x []float64) bool { + var dedup = make(map[float64]bool) + for _, v := range x { + if _, ok := dedup[v]; !ok { + dedup[v] = true + } else { + return true + } + } + return false +} + +var defaultParameterTempate = ` +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "fmt" + "sync" + "github.com/BurntSushi/toml" +) + +//all parameters in the system +type {{.ParameterStructName}} struct{ + //read and write lock + rwlock sync.RWMutex +{{range .Parameter}} + {{ printf "/**\n\tName:\t%s\n\tScope:\t%s\n\tAccess:\t%s\n\tDataType:\t%s\n\tDomainType:\t%s\n\tValues:\t%s\n\tComment:\t%s\n\tUpdateMode:\t%s\n\t*/" + .Name .Scope .Access .DataType .DomainType .Values .Comment .UpdateMode + }} + {{ printf "%s %s" .Name .DataType }} +{{end}} + + //parameter name -> parameter definition string + name2definition map[string]string +}//end {{.ParameterStructName}} + +//all parameters can be set in the configuration file. +type {{.ConfigurationStructName}} struct{ + //read and write lock + rwlock sync.RWMutex + +{{range .Parameter}} + {{ if ne .UpdateMode "fix"}} + {{ printf "/**\n\tName:\t%s\n\tScope:\t%s\n\tAccess:\t%s\n\tDataType:\t%s\n\tDomainType:\t%s\n\tValues:\t%s\n\tComment:\t%s\n\tUpdateMode:\t%s\n\t*/" + .Name .Scope .Access .DataType .DomainType .Values .Comment .UpdateMode + }} + {{ printf "%s %s ` + "`toml:" + `\"%s\"` + "`" + `" .CapitalName .DataType .Name }} + + {{end}} +{{end}} + + //parameter name -> updated flag + name2updatedFlags map[string]bool +}//end {{.ConfigurationStructName}} + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (ap *{{.ParameterStructName}}) prepareAnything(){ + if ap.name2definition == nil { + ap.name2definition = make(map[string]string) + } +} + +/** +set parameter and its string of the definition. +*/ +func (ap *{{.ParameterStructName}}) PrepareDefinition(){ + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + ap.prepareAnything() + {{range .Parameter}} + {{ printf "ap.name2definition[\"%s\"] = \"\tName:\t%s\tScope:\t%s\tAccess:\t%s\tDataType:\t%s\tDomainType:\t%s\tValues:\t%s\tComment:\t%s\tUpdateMode:\t%s\t\"" + .Name .Name .Scope .Access .DataType .DomainType .Values .Comment .UpdateMode + }} + {{end}} +} + +/** +get the definition of the parameter. +*/ +func (ap *{{.ParameterStructName}}) GetDefinition(name string)(string,error){ + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if p,ok := ap.name2definition[name];!ok{ + return "",fmt.Errorf("there is no parameter %s",name) + }else{ + return p,nil + } +} + +/** +check if there is the parameter +*/ +func (ap *{{.ParameterStructName}}) HasParameter(name string)bool{ + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if _,ok := ap.name2definition[name];!ok{ + return false + }else{ + return true + } +} + +/** +Load the initial values of all parameters. +*/ +func (ap *{{.ParameterStructName}}) LoadInitialValues()error{ + ap.PrepareDefinition() + var err error + {{range .Parameter}} + + {{if eq .DataType "string"}} + {{.Name}}choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "\"%s\"" .}}, + {{end}} + } + if len({{.Name}}choices) != 0{ + if err = ap.set{{.CapitalName}}( {{.Name}}choices[0] ) ; err != nil{ + return fmt.Errorf("set%s failed.error:%v",{{printf "\"%s\"" .CapitalName}},err) + } + }else{ + //empty string + if err = ap.set{{.CapitalName}}( "" ) ; err != nil{ + return fmt.Errorf("set%s failed.error:%v",{{printf "\"%s\"" .CapitalName}},err) + } + } + {{else}} + {{.Name}}choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "%s" .}}, + {{end}} + } + if len({{.Name}}choices) != 0{ + if err = ap.set{{.CapitalName}}( {{.Name}}choices[0] ) ; err != nil{ + return fmt.Errorf("set%s failed.error:%v",{{printf "\"%s\"" .CapitalName}},err) + } + }else{ + {{if eq .DataType "bool"}} + if err = ap.set{{.CapitalName}}( false ) ; err != nil{ + return fmt.Errorf("set%s failed.error:%v",{{printf "\"%s\"" .CapitalName}},err) + } + {{else if eq .DataType "int64"}} + if err = ap.set{{.CapitalName}}( 0 ) ; err != nil{ + return fmt.Errorf("set%s failed.error:%v",{{printf "\"%s\"" .CapitalName}},err) + } + {{else if eq .DataType "float64"}} + if err = ap.set{{.CapitalName}}( 0.0 ) ; err != nil{ + return fmt.Errorf("set%s failed.error:%v",{{printf "\"%s\"" .CapitalName}},err) + } + {{end}} + } + {{end}} + {{end}} + return nil +} + +{{with $Params := .}} +{{range $Params.Parameter}} +/** +Get the value of the parameter {{.Name}} +*/ +func (ap * {{$Params.ParameterStructName}} ) Get{{.CapitalName}}() {{.DataType}} { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.{{.Name}} +} +{{end}} +{{end}} + + +{{with $Params := .}} +{{range $Params.Parameter}} +{{ if ne .UpdateMode "fix"}} +/** +Set the value of the parameter {{.Name}} +*/ +func (ap * {{$Params.ParameterStructName}} ) Set{{.CapitalName}}(value {{.DataType}})error { + return ap.set{{.CapitalName}}(value) +} +{{end}} +{{end}} +{{end}} + +{{with $Params := .}} +{{range $Params.Parameter}} +/** +Set the value of the parameter {{.Name}} +*/ +func (ap * {{$Params.ParameterStructName}} ) set{{.CapitalName}}(value {{.DataType}})error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + {{if eq .DataType "bool"}} + + {{if eq .DomainType "set"}} + choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "%s" .}}, + {{end}} + } + if len( choices ) != 0{ + if !isInSliceBool(value, choices){ + return fmt.Errorf("set{{.CapitalName}},the value %t is not in set %v",value,choices) + } + }//else means any bool value: true or false + {{else}} + return fmt.Errorf("the bool type does not support domainType %s",{{printf "\"%s\"" .DomainType}}) + {{end}} + + {{else if eq .DataType "string"}} + + {{if eq .DomainType "set"}} + choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "\"%s\"" .}}, + {{end}} + } + if len( choices ) != 0{ + if !isInSlice(value, choices){ + return fmt.Errorf("set{{.CapitalName}},the value %s is not in set %v",value,choices) + } + }//else means any string + {{else}} + return fmt.Errorf("the string type does not support domainType %s",{{printf "\"%s\"" .DomainType}}) + {{end}} + + {{else if eq .DataType "int64"}} + + {{if eq .DomainType "set"}} + choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "%s" .}}, + {{end}} + } + if len( choices ) != 0{ + if !isInSliceInt64(value, choices){ + return fmt.Errorf("set{{.CapitalName}},the value %d is not in set %v",value,choices) + } + }//else means any int64 + {{else if eq .DomainType "range"}} + choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "%s" .}}, + {{end}} + } + if !(value >= choices[1] && value <= choices[2]){ + return fmt.Errorf("set{{.CapitalName}},the value %d is not in the range [%d,%d]",value,choices[1],choices[2]) + } + {{else}} + return fmt.Errorf("the int64 type does not support domainType %s",{{printf "\"%s\"" .DomainType}}) + {{end}} + + {{else if eq .DataType "float64"}} + + {{if eq .DomainType "set"}} + choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "%s" .}}, + {{end}} + } + if len( choices ) != 0{ + if !isInSliceFloat64(value, choices){ + return fmt.Errorf("set{{.CapitalName}},the value %f is not in set %v",value,choices) + } + }//else means any float64 + {{else if eq .DomainType "range"}} + choices :=[]{{.DataType}} { + {{range .Values}} + {{printf "%s" .}}, + {{end}} + } + if !(value >= choices[1] && value <= choices[2]){ + return fmt.Errorf("set{{.CapitalName}},the value %f is not in the range [%f,%f]",value,choices[1],choices[2]) + } + {{else}} + return fmt.Errorf("the float64 type does not support domainType %s",{{printf "\"%s\"" .DomainType}}) + {{end}} + {{end}} + + ap.{{.Name}} = value + return nil +} +{{end}} +{{end}} + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (config *{{.ConfigurationStructName}}) prepareAnything(){ + if config.name2updatedFlags == nil { + config.name2updatedFlags = make(map[string]bool) + } +} + +/** +reset update flags of configuration items +*/ +func (config *{{.ConfigurationStructName}}) resetUpdatedFlags(){ + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + {{range .Parameter}} + {{ if ne .UpdateMode "fix"}} + {{ printf "config.name2updatedFlags[\"%s\"] = false" .Name}} + {{end}} + {{end}} +} + +/** +set update flag of configuration item +*/ +func (config *{{.ConfigurationStructName}}) setUpdatedFlag(name string,updated bool){ + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + config.name2updatedFlags[name] = updated +} + +/** +get update flag of configuration item +*/ +func (config *{{.ConfigurationStructName}}) getUpdatedFlag(name string)bool{ + config.rwlock.RLock() + defer config.rwlock.RUnlock() + config.prepareAnything() + return config.name2updatedFlags[name] +} + +/** +Load parameters' values in the configuration string. +*/ +func (config *{{.ConfigurationStructName}}) LoadConfigurationFromString(input string) error { + config.resetUpdatedFlags() + + metadata, err := toml.Decode(input, config); + if err != nil { + return err + }else if failed := metadata.Undecoded() ; len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v",failedItems,err) + } + + for _,k := range metadata.Keys(){ + config.setUpdatedFlag(k[0],true) + } + + return nil +} + +/** +Load parameters' values in the configuration file. +*/ +func (config *{{.ConfigurationStructName}}) LoadConfigurationFromFile(fname string) error { + config.resetUpdatedFlags() + + metadata, err := toml.DecodeFile(fname, config); + if err != nil { + return err + }else if failed := metadata.Undecoded() ; len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v",failedItems,err) + } + + for _,k := range metadata.Keys(){ + config.setUpdatedFlag(k[0],true) + } + + return nil +} + +/** +Update parameters' values with configuration. +*/ +func (ap * {{.ParameterStructName}} ) UpdateParametersWithConfiguration(config *{{.ConfigurationStructName}})error{ + var err error + {{range .Parameter}} + {{ if ne .UpdateMode "fix"}} + if config.getUpdatedFlag("{{.Name}}"){ + if err = ap.set{{.CapitalName}}(config.{{.CapitalName}}); err != nil{ + return fmt.Errorf("update parameter {{.Name}} failed.error:%v",err) + } + } + {{end}} + {{end}} + return nil +} + +/** +Load configuration from file into {{.ConfigurationStructName}}. +Then update items into {{.ParameterStructName}} +*/ +func Load{{.ConfigurationStructName}}FromFile(filename string,params *{{.ParameterStructName}}) error{ + config := &{{.ConfigurationStructName}}{} + if err := config.LoadConfigurationFromFile(filename); err != nil{ + return err + } + + if err := params.UpdateParametersWithConfiguration(config); err != nil{ + return err + } + return nil +} +` + +var defaultConfigurationTemplate = ` +# Code generated by tool; DO NOT EDIT. +{{range $index,$param := .Parameter}} +{{ if ne .UpdateMode "fix"}} + {{ printf "\n#\tName:\t%s\n#\tScope:\t%s\n#\tAccess:\t%s\n#\tDataType:\t%s\n#\tDomainType:\t%s\n#\tValues:\t%s\n#\tComment:\t%s\n#\tUpdateMode:\t%s\n\t" + .Name .Scope .Access .DataType .DomainType .Values .Comment .UpdateMode + }} + + {{- with $count := len .Values -}} + {{- if ne 0 $count -}} + {{- if eq $param.DataType "string" -}} + {{- $param.Name -}} = "{{- index $param.Values 0 -}}" + {{- else -}} + {{- $param.Name -}} = {{- index $param.Values 0 -}} + {{- end -}} + {{- end -}} + {{- else -}} + {{- if eq $param.DataType "string" -}} + {{- $param.Name -}} = "" + {{- else if eq $param.DataType "bool" -}} + {{- $param.Name -}} = false + {{- else if eq $param.DataType "int64" -}} + {{- $param.Name -}} = 0 + {{- else if eq $param.DataType "float64" -}} + {{- $param.Name -}} = 0.0 + {{- end -}} + {{- end -}} +{{end}} +{{end}} +` + +var defaultOperationTestTemplate = ` +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "sync" + "testing" +) + +func Test{{.ParameterStructName}}_LoadInitialValues(t *testing.T) { + ap := &{{.ParameterStructName}}{} + if err :=ap.LoadInitialValues(); err!=nil{ + t.Errorf("LoadInitialValues failed. error:%v",err) + } +} + +func is{{.ConfigurationStructName}}Equal(c1,c2 {{.ConfigurationStructName}}) bool { + +{{range .Parameter}} +{{ if ne .UpdateMode "fix"}} + if c1.{{.CapitalName}} != c2.{{.CapitalName}} { + return false + } +{{end}} +{{end}} + + return true +} + +func Test_{{.ConfigurationStructName}}_LoadConfigurationFromString(t *testing.T) { + t1 := ` + "`" + ` +{{range $index,$param := .Parameter}} +{{ if ne .UpdateMode "fix"}} + {{- with $count := len .Values -}} + {{- if ne 0 $count -}} + {{- if eq $param.DataType "string" -}} + {{- $param.Name -}} = "{{- index $param.Values 0 -}}" + {{- else -}} + {{- $param.Name -}} = {{- index $param.Values 0 -}} + {{- end -}} + {{- end -}} + {{- else -}} + {{- if eq $param.DataType "string" -}} + {{- $param.Name -}} = "" + {{- else if eq $param.DataType "bool" -}} + {{- $param.Name -}} = false + {{- else if eq $param.DataType "int64" -}} + {{- $param.Name -}} = 0 + {{- else if eq $param.DataType "float64" -}} + {{- $param.Name -}} = 0.0 + {{- end -}} + {{- end -}} +{{end}} +{{end}} +` + "`" + ` + t1_config:={{.ConfigurationStructName}}{ + rwlock: sync.RWMutex{}, + +{{range $index,$param := .Parameter}} +{{ if ne .UpdateMode "fix"}} + {{- with $count := len .Values -}} + {{- if ne 0 $count -}} + {{- if eq $param.DataType "string" -}} + {{- $param.CapitalName -}} : "{{- index $param.Values 0 -}}" , + {{- else -}} + {{- $param.CapitalName -}} : {{- index $param.Values 0 -}} , + {{- end -}} + {{- end -}} + {{- else -}} + {{- if eq $param.DataType "string" -}} + {{- $param.CapitalName -}} : "" , + {{- else if eq $param.DataType "bool" -}} + {{- $param.CapitalName -}} : false , + {{- else if eq $param.DataType "int64" -}} + {{- $param.CapitalName -}} : 0 , + {{- else if eq $param.DataType "float64" -}} + {{- $param.CapitalName -}} : 0.0 , + {{- end -}} + {{- end -}} +{{end}} +{{end}} + + name2updatedFlags: nil, + } + + type args struct { + input string + config {{.ConfigurationStructName}} + } + tests := []struct { + name string + args args + wantErr bool + wantErr2 bool + wantErr3 bool + }{ + {"t1",args{t1,t1_config},false,false,false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ap := &{{.ParameterStructName}}{} + if err := ap.LoadInitialValues(); err != nil{ + t.Errorf("LoadInitialValues failed.error %v",err) + } + config := &{{.ConfigurationStructName}}{} + if err := config.LoadConfigurationFromString(tt.args.input); (err != nil) != tt.wantErr { + t.Errorf("LoadConfigurationFromString() error = %v, wantErr %v", err, tt.wantErr) + }else if err != nil{ + return + } + + if err := ap.UpdateParametersWithConfiguration(config); (err != nil) != tt.wantErr2{ + t.Errorf("UpdateParametersWithConfiguration failed. error:%v",err) + } + + if ( is{{.ConfigurationStructName}}Equal(*config,tt.args.config) != true ) != tt.wantErr3{ + t.Errorf("Configuration are not equal. %v vs %v ",*config,tt.args.config) + return + } + }) + } +} +` + +/** +Analyse the template files. +Generate configuration file, operation interfaces. +*/ +type ConfigurationFileGenerator interface { + /** + Input: parameter definition file name + Output: + 1. operation interface and code for parameters + 2. configuraion file for parameters + */ + Generate() error +} + +type ConfigurationFileGeneratorImpl struct { + //the name of the parameter definition + parameterDefinitionFileName string + + //the template string for the auto generated parameter operation interfaces and classes. + parameterTemplate string + + //the template string for the auto generated initial configuration file. + configurationTemplate string + + //the template string for the auto generated parameter operation interfaces test cases. + parameterTestCasesTemplate string +} + +func (cfgi *ConfigurationFileGeneratorImpl) Generate() error { + defDir, err := filepath.Abs(filepath.Dir(cfgi.parameterDefinitionFileName)) + if err != nil { + return fmt.Errorf("Get the directory of parameter defintion file failed.error:%v", err) + } + + params := ¶meters{} + if err := params.LoadParametersDefinitionFromFile(cfgi.parameterDefinitionFileName); err != nil { + return fmt.Errorf("LoadParametersDefinitionFromFile failed.error:%v", err) + } + + parameterTmpl, err := template.New("MakeParameterTemplate").Parse(cfgi.parameterTemplate) + if err != nil { + return fmt.Errorf("Make parameter template failed. error:%v", err) + } + + f, err := os.Create(defDir + "/" + params.OperationFileName + ".go") + if err != nil { + return err + } + defer f.Close() + + err = parameterTmpl.Execute(f, params) + if err != nil { + return err + } + + tomlTmpl, err := template.New("MakeConfigurationTemplate").Parse(cfgi.configurationTemplate) + if err != nil { + return err + } + + tomlf, err := os.Create(defDir + "/" + params.ConfigurationFileName + ".toml") + if err != nil { + return err + } + defer tomlf.Close() + + err = tomlTmpl.Execute(tomlf, params) + if err != nil { + return err + } + + testCasesTmpl, err := template.New("MakeTestCasesTemplate").Parse(cfgi.parameterTestCasesTemplate) + if err != nil { + return err + } + + testCasesf, err := os.Create(defDir + "/" + params.OperationFileName + "_test.go") + if err != nil { + return err + } + defer testCasesf.Close() + + err = testCasesTmpl.Execute(testCasesf, params) + if err != nil { + return err + } + + return nil +} + +/** +load items from configuration file periodly. +*/ +type ConfigurationFileHotLoader interface { + /** + register a configuration file into the loader. + path : the path of the configuration file + period: load the configration every period + configObject: the target that will be updated + */ + Register(path string, period int64, configObject interface{}) + + /** + unregister a configuration file from the loader. + the configuration file will be loaded again. + */ + Unregister(path string) +} + +func NewConfigurationFileGenerator(defFileName string) ConfigurationFileGenerator { + return &ConfigurationFileGeneratorImpl{ + parameterDefinitionFileName: defFileName, + parameterTemplate: defaultParameterTempate, + configurationTemplate: defaultConfigurationTemplate, + parameterTestCasesTemplate: defaultOperationTestTemplate, + } +} diff --git a/pkg/config/test/parameters.go b/pkg/config/test/parameters.go new file mode 100644 index 0000000000000000000000000000000000000000..bb821bfbc2311b12738c5a27e0cc6314ebc806b0 --- /dev/null +++ b/pkg/config/test/parameters.go @@ -0,0 +1,1333 @@ +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "fmt" + "github.com/BurntSushi/toml" + "sync" +) + +//all parameters in the system +type AllParameters struct { + //read and write lock + rwlock sync.RWMutex + + /** + Name: boolSet1 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [true] + Comment: boolSet1 + UpdateMode: dynamic + */ + boolSet1 bool + + /** + Name: boolSet2 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [false] + Comment: boolSet2 + UpdateMode: hotload + */ + boolSet2 bool + + /** + Name: boolSet3 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [] + Comment: boolSet3 + UpdateMode: dynamic + */ + boolSet3 bool + + /** + Name: stringSet1 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [ss1 ss2 ss3] + Comment: stringSet1 + UpdateMode: dynamic + */ + stringSet1 string + + /** + Name: stringSet2 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [] + Comment: stringSet2 + UpdateMode: dynamic + */ + stringSet2 string + + /** + Name: int64set1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [1 2 3 4 5 6] + Comment: int64Set1 + UpdateMode: dynamic + */ + int64set1 int64 + + /** + Name: int64set2 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [1 3 5 7] + Comment: int64Set2 + UpdateMode: fix + */ + int64set2 int64 + + /** + Name: int64set3 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [] + Comment: int64Set3 + UpdateMode: dynamic + */ + int64set3 int64 + + /** + Name: int64Range1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: range + Values: [1000 0 10000] + Comment: int64Range1 + UpdateMode: dynamic + */ + int64Range1 int64 + + /** + Name: float64set1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [1.0 2.0 3.0 4.00 5.0 6.0] + Comment: float64Set1 + UpdateMode: dynamic + */ + float64set1 float64 + + /** + Name: float64set2 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [1.001 3.003 5.005 7.007] + Comment: float64Set2 + UpdateMode: fix + */ + float64set2 float64 + + /** + Name: float64set3 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [] + Comment: float64Set3 + UpdateMode: dynamic + */ + float64set3 float64 + + /** + Name: float64Range1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: range + Values: [1000.01 0.02 10000.03] + Comment: float64Range1 + UpdateMode: dynamic + */ + float64Range1 float64 + + //parameter name -> parameter definition string + name2definition map[string]string +} //end AllParameters + +//all parameters can be set in the configuration file. +type configuration struct { + //read and write lock + rwlock sync.RWMutex + + /** + Name: boolSet1 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [true] + Comment: boolSet1 + UpdateMode: dynamic + */ + BoolSet1 bool `toml:"boolSet1"` + + /** + Name: boolSet2 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [false] + Comment: boolSet2 + UpdateMode: hotload + */ + BoolSet2 bool `toml:"boolSet2"` + + /** + Name: boolSet3 + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [] + Comment: boolSet3 + UpdateMode: dynamic + */ + BoolSet3 bool `toml:"boolSet3"` + + /** + Name: stringSet1 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [ss1 ss2 ss3] + Comment: stringSet1 + UpdateMode: dynamic + */ + StringSet1 string `toml:"stringSet1"` + + /** + Name: stringSet2 + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [] + Comment: stringSet2 + UpdateMode: dynamic + */ + StringSet2 string `toml:"stringSet2"` + + /** + Name: int64set1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [1 2 3 4 5 6] + Comment: int64Set1 + UpdateMode: dynamic + */ + Int64set1 int64 `toml:"int64set1"` + + /** + Name: int64set3 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [] + Comment: int64Set3 + UpdateMode: dynamic + */ + Int64set3 int64 `toml:"int64set3"` + + /** + Name: int64Range1 + Scope: [global] + Access: [file] + DataType: int64 + DomainType: range + Values: [1000 0 10000] + Comment: int64Range1 + UpdateMode: dynamic + */ + Int64Range1 int64 `toml:"int64Range1"` + + /** + Name: float64set1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [1.0 2.0 3.0 4.00 5.0 6.0] + Comment: float64Set1 + UpdateMode: dynamic + */ + Float64set1 float64 `toml:"float64set1"` + + /** + Name: float64set3 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: set + Values: [] + Comment: float64Set3 + UpdateMode: dynamic + */ + Float64set3 float64 `toml:"float64set3"` + + /** + Name: float64Range1 + Scope: [global] + Access: [file] + DataType: float64 + DomainType: range + Values: [1000.01 0.02 10000.03] + Comment: float64Range1 + UpdateMode: dynamic + */ + Float64Range1 float64 `toml:"float64Range1"` + + //parameter name -> updated flag + name2updatedFlags map[string]bool +} //end configuration + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (ap *AllParameters) prepareAnything() { + if ap.name2definition == nil { + ap.name2definition = make(map[string]string) + } +} + +/** +set parameter and its string of the definition. +*/ +func (ap *AllParameters) PrepareDefinition() { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + ap.prepareAnything() + + ap.name2definition["boolSet1"] = " Name: boolSet1 Scope: [global] Access: [file] DataType: bool DomainType: set Values: [true] Comment: boolSet1 UpdateMode: dynamic " + + ap.name2definition["boolSet2"] = " Name: boolSet2 Scope: [global] Access: [file] DataType: bool DomainType: set Values: [false] Comment: boolSet2 UpdateMode: hotload " + + ap.name2definition["boolSet3"] = " Name: boolSet3 Scope: [global] Access: [file] DataType: bool DomainType: set Values: [] Comment: boolSet3 UpdateMode: dynamic " + + ap.name2definition["stringSet1"] = " Name: stringSet1 Scope: [global] Access: [file] DataType: string DomainType: set Values: [ss1 ss2 ss3] Comment: stringSet1 UpdateMode: dynamic " + + ap.name2definition["stringSet2"] = " Name: stringSet2 Scope: [global] Access: [file] DataType: string DomainType: set Values: [] Comment: stringSet2 UpdateMode: dynamic " + + ap.name2definition["int64set1"] = " Name: int64set1 Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [1 2 3 4 5 6] Comment: int64Set1 UpdateMode: dynamic " + + ap.name2definition["int64set2"] = " Name: int64set2 Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [1 3 5 7] Comment: int64Set2 UpdateMode: fix " + + ap.name2definition["int64set3"] = " Name: int64set3 Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [] Comment: int64Set3 UpdateMode: dynamic " + + ap.name2definition["int64Range1"] = " Name: int64Range1 Scope: [global] Access: [file] DataType: int64 DomainType: range Values: [1000 0 10000] Comment: int64Range1 UpdateMode: dynamic " + + ap.name2definition["float64set1"] = " Name: float64set1 Scope: [global] Access: [file] DataType: float64 DomainType: set Values: [1.0 2.0 3.0 4.00 5.0 6.0] Comment: float64Set1 UpdateMode: dynamic " + + ap.name2definition["float64set2"] = " Name: float64set2 Scope: [global] Access: [file] DataType: float64 DomainType: set Values: [1.001 3.003 5.005 7.007] Comment: float64Set2 UpdateMode: fix " + + ap.name2definition["float64set3"] = " Name: float64set3 Scope: [global] Access: [file] DataType: float64 DomainType: set Values: [] Comment: float64Set3 UpdateMode: dynamic " + + ap.name2definition["float64Range1"] = " Name: float64Range1 Scope: [global] Access: [file] DataType: float64 DomainType: range Values: [1000.01 0.02 10000.03] Comment: float64Range1 UpdateMode: dynamic " + +} + +/** +get the definition of the parameter. +*/ +func (ap *AllParameters) GetDefinition(name string) (string, error) { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if p, ok := ap.name2definition[name]; !ok { + return "", fmt.Errorf("there is no parameter %s", name) + } else { + return p, nil + } +} + +/** +check if there is the parameter +*/ +func (ap *AllParameters) HasParameter(name string) bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if _, ok := ap.name2definition[name]; !ok { + return false + } else { + return true + } +} + +/** +Load the initial values of all parameters. +*/ +func (ap *AllParameters) LoadInitialValues() error { + ap.PrepareDefinition() + var err error + + boolSet1choices := []bool{ + + true, + } + if len(boolSet1choices) != 0 { + if err = ap.setBoolSet1(boolSet1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet1", err) + } + } else { + + if err = ap.setBoolSet1(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet1", err) + } + + } + + boolSet2choices := []bool{ + + false, + } + if len(boolSet2choices) != 0 { + if err = ap.setBoolSet2(boolSet2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet2", err) + } + } else { + + if err = ap.setBoolSet2(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet2", err) + } + + } + + boolSet3choices := []bool{} + if len(boolSet3choices) != 0 { + if err = ap.setBoolSet3(boolSet3choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet3", err) + } + } else { + + if err = ap.setBoolSet3(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "BoolSet3", err) + } + + } + + stringSet1choices := []string{ + + "ss1", + + "ss2", + + "ss3", + } + if len(stringSet1choices) != 0 { + if err = ap.setStringSet1(stringSet1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet1", err) + } + } else { + //empty string + if err = ap.setStringSet1(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet1", err) + } + } + + stringSet2choices := []string{} + if len(stringSet2choices) != 0 { + if err = ap.setStringSet2(stringSet2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet2", err) + } + } else { + //empty string + if err = ap.setStringSet2(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "StringSet2", err) + } + } + + int64set1choices := []int64{ + + 1, + + 2, + + 3, + + 4, + + 5, + + 6, + } + if len(int64set1choices) != 0 { + if err = ap.setInt64set1(int64set1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set1", err) + } + } else { + + if err = ap.setInt64set1(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set1", err) + } + + } + + int64set2choices := []int64{ + + 1, + + 3, + + 5, + + 7, + } + if len(int64set2choices) != 0 { + if err = ap.setInt64set2(int64set2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set2", err) + } + } else { + + if err = ap.setInt64set2(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set2", err) + } + + } + + int64set3choices := []int64{} + if len(int64set3choices) != 0 { + if err = ap.setInt64set3(int64set3choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set3", err) + } + } else { + + if err = ap.setInt64set3(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64set3", err) + } + + } + + int64Range1choices := []int64{ + + 1000, + + 0, + + 10000, + } + if len(int64Range1choices) != 0 { + if err = ap.setInt64Range1(int64Range1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64Range1", err) + } + } else { + + if err = ap.setInt64Range1(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Int64Range1", err) + } + + } + + float64set1choices := []float64{ + + 1.0, + + 2.0, + + 3.0, + + 4.00, + + 5.0, + + 6.0, + } + if len(float64set1choices) != 0 { + if err = ap.setFloat64set1(float64set1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set1", err) + } + } else { + + if err = ap.setFloat64set1(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set1", err) + } + + } + + float64set2choices := []float64{ + + 1.001, + + 3.003, + + 5.005, + + 7.007, + } + if len(float64set2choices) != 0 { + if err = ap.setFloat64set2(float64set2choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set2", err) + } + } else { + + if err = ap.setFloat64set2(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set2", err) + } + + } + + float64set3choices := []float64{} + if len(float64set3choices) != 0 { + if err = ap.setFloat64set3(float64set3choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set3", err) + } + } else { + + if err = ap.setFloat64set3(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64set3", err) + } + + } + + float64Range1choices := []float64{ + + 1000.01, + + 0.02, + + 10000.03, + } + if len(float64Range1choices) != 0 { + if err = ap.setFloat64Range1(float64Range1choices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64Range1", err) + } + } else { + + if err = ap.setFloat64Range1(0.0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Float64Range1", err) + } + + } + + return nil +} + +/** +Get the value of the parameter boolSet1 +*/ +func (ap *AllParameters) GetBoolSet1() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.boolSet1 +} + +/** +Get the value of the parameter boolSet2 +*/ +func (ap *AllParameters) GetBoolSet2() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.boolSet2 +} + +/** +Get the value of the parameter boolSet3 +*/ +func (ap *AllParameters) GetBoolSet3() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.boolSet3 +} + +/** +Get the value of the parameter stringSet1 +*/ +func (ap *AllParameters) GetStringSet1() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.stringSet1 +} + +/** +Get the value of the parameter stringSet2 +*/ +func (ap *AllParameters) GetStringSet2() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.stringSet2 +} + +/** +Get the value of the parameter int64set1 +*/ +func (ap *AllParameters) GetInt64set1() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64set1 +} + +/** +Get the value of the parameter int64set2 +*/ +func (ap *AllParameters) GetInt64set2() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64set2 +} + +/** +Get the value of the parameter int64set3 +*/ +func (ap *AllParameters) GetInt64set3() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64set3 +} + +/** +Get the value of the parameter int64Range1 +*/ +func (ap *AllParameters) GetInt64Range1() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.int64Range1 +} + +/** +Get the value of the parameter float64set1 +*/ +func (ap *AllParameters) GetFloat64set1() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64set1 +} + +/** +Get the value of the parameter float64set2 +*/ +func (ap *AllParameters) GetFloat64set2() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64set2 +} + +/** +Get the value of the parameter float64set3 +*/ +func (ap *AllParameters) GetFloat64set3() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64set3 +} + +/** +Get the value of the parameter float64Range1 +*/ +func (ap *AllParameters) GetFloat64Range1() float64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.float64Range1 +} + +/** +Set the value of the parameter boolSet1 +*/ +func (ap *AllParameters) SetBoolSet1(value bool) error { + return ap.setBoolSet1(value) +} + +/** +Set the value of the parameter boolSet2 +*/ +func (ap *AllParameters) SetBoolSet2(value bool) error { + return ap.setBoolSet2(value) +} + +/** +Set the value of the parameter boolSet3 +*/ +func (ap *AllParameters) SetBoolSet3(value bool) error { + return ap.setBoolSet3(value) +} + +/** +Set the value of the parameter stringSet1 +*/ +func (ap *AllParameters) SetStringSet1(value string) error { + return ap.setStringSet1(value) +} + +/** +Set the value of the parameter stringSet2 +*/ +func (ap *AllParameters) SetStringSet2(value string) error { + return ap.setStringSet2(value) +} + +/** +Set the value of the parameter int64set1 +*/ +func (ap *AllParameters) SetInt64set1(value int64) error { + return ap.setInt64set1(value) +} + +/** +Set the value of the parameter int64set3 +*/ +func (ap *AllParameters) SetInt64set3(value int64) error { + return ap.setInt64set3(value) +} + +/** +Set the value of the parameter int64Range1 +*/ +func (ap *AllParameters) SetInt64Range1(value int64) error { + return ap.setInt64Range1(value) +} + +/** +Set the value of the parameter float64set1 +*/ +func (ap *AllParameters) SetFloat64set1(value float64) error { + return ap.setFloat64set1(value) +} + +/** +Set the value of the parameter float64set3 +*/ +func (ap *AllParameters) SetFloat64set3(value float64) error { + return ap.setFloat64set3(value) +} + +/** +Set the value of the parameter float64Range1 +*/ +func (ap *AllParameters) SetFloat64Range1(value float64) error { + return ap.setFloat64Range1(value) +} + +/** +Set the value of the parameter boolSet1 +*/ +func (ap *AllParameters) setBoolSet1(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{ + + true, + } + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setBoolSet1,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.boolSet1 = value + return nil +} + +/** +Set the value of the parameter boolSet2 +*/ +func (ap *AllParameters) setBoolSet2(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{ + + false, + } + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setBoolSet2,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.boolSet2 = value + return nil +} + +/** +Set the value of the parameter boolSet3 +*/ +func (ap *AllParameters) setBoolSet3(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{} + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setBoolSet3,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.boolSet3 = value + return nil +} + +/** +Set the value of the parameter stringSet1 +*/ +func (ap *AllParameters) setStringSet1(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "ss1", + + "ss2", + + "ss3", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setStringSet1,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.stringSet1 = value + return nil +} + +/** +Set the value of the parameter stringSet2 +*/ +func (ap *AllParameters) setStringSet2(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{} + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setStringSet2,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.stringSet2 = value + return nil +} + +/** +Set the value of the parameter int64set1 +*/ +func (ap *AllParameters) setInt64set1(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 1, + + 2, + + 3, + + 4, + + 5, + + 6, + } + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setInt64set1,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.int64set1 = value + return nil +} + +/** +Set the value of the parameter int64set2 +*/ +func (ap *AllParameters) setInt64set2(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 1, + + 3, + + 5, + + 7, + } + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setInt64set2,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.int64set2 = value + return nil +} + +/** +Set the value of the parameter int64set3 +*/ +func (ap *AllParameters) setInt64set3(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{} + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setInt64set3,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.int64set3 = value + return nil +} + +/** +Set the value of the parameter int64Range1 +*/ +func (ap *AllParameters) setInt64Range1(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 1000, + + 0, + + 10000, + } + if !(value >= choices[1] && value <= choices[2]) { + return fmt.Errorf("setInt64Range1,the value %d is not in the range [%d,%d]", value, choices[1], choices[2]) + } + + ap.int64Range1 = value + return nil +} + +/** +Set the value of the parameter float64set1 +*/ +func (ap *AllParameters) setFloat64set1(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{ + + 1.0, + + 2.0, + + 3.0, + + 4.00, + + 5.0, + + 6.0, + } + if len(choices) != 0 { + if !isInSliceFloat64(value, choices) { + return fmt.Errorf("setFloat64set1,the value %f is not in set %v", value, choices) + } + } //else means any float64 + + ap.float64set1 = value + return nil +} + +/** +Set the value of the parameter float64set2 +*/ +func (ap *AllParameters) setFloat64set2(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{ + + 1.001, + + 3.003, + + 5.005, + + 7.007, + } + if len(choices) != 0 { + if !isInSliceFloat64(value, choices) { + return fmt.Errorf("setFloat64set2,the value %f is not in set %v", value, choices) + } + } //else means any float64 + + ap.float64set2 = value + return nil +} + +/** +Set the value of the parameter float64set3 +*/ +func (ap *AllParameters) setFloat64set3(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{} + if len(choices) != 0 { + if !isInSliceFloat64(value, choices) { + return fmt.Errorf("setFloat64set3,the value %f is not in set %v", value, choices) + } + } //else means any float64 + + ap.float64set3 = value + return nil +} + +/** +Set the value of the parameter float64Range1 +*/ +func (ap *AllParameters) setFloat64Range1(value float64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []float64{ + + 1000.01, + + 0.02, + + 10000.03, + } + if !(value >= choices[1] && value <= choices[2]) { + return fmt.Errorf("setFloat64Range1,the value %f is not in the range [%f,%f]", value, choices[1], choices[2]) + } + + ap.float64Range1 = value + return nil +} + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (config *configuration) prepareAnything() { + if config.name2updatedFlags == nil { + config.name2updatedFlags = make(map[string]bool) + } +} + +/** +reset update flags of configuration items +*/ +func (config *configuration) resetUpdatedFlags() { + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + + config.name2updatedFlags["boolSet1"] = false + + config.name2updatedFlags["boolSet2"] = false + + config.name2updatedFlags["boolSet3"] = false + + config.name2updatedFlags["stringSet1"] = false + + config.name2updatedFlags["stringSet2"] = false + + config.name2updatedFlags["int64set1"] = false + + config.name2updatedFlags["int64set3"] = false + + config.name2updatedFlags["int64Range1"] = false + + config.name2updatedFlags["float64set1"] = false + + config.name2updatedFlags["float64set3"] = false + + config.name2updatedFlags["float64Range1"] = false + +} + +/** +set update flag of configuration item +*/ +func (config *configuration) setUpdatedFlag(name string, updated bool) { + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + config.name2updatedFlags[name] = updated +} + +/** +get update flag of configuration item +*/ +func (config *configuration) getUpdatedFlag(name string) bool { + config.rwlock.RLock() + defer config.rwlock.RUnlock() + config.prepareAnything() + return config.name2updatedFlags[name] +} + +/** +Load parameters' values in the configuration string. +*/ +func (config *configuration) LoadConfigurationFromString(input string) error { + config.resetUpdatedFlags() + + metadata, err := toml.Decode(input, config) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + for _, k := range metadata.Keys() { + config.setUpdatedFlag(k[0], true) + } + + return nil +} + +/** +Load parameters' values in the configuration file. +*/ +func (config *configuration) LoadConfigurationFromFile(fname string) error { + config.resetUpdatedFlags() + + metadata, err := toml.DecodeFile(fname, config) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + for _, k := range metadata.Keys() { + config.setUpdatedFlag(k[0], true) + } + + return nil +} + +/** +Update parameters' values with configuration. +*/ +func (ap *AllParameters) UpdateParametersWithConfiguration(config *configuration) error { + var err error + + if config.getUpdatedFlag("boolSet1") { + if err = ap.setBoolSet1(config.BoolSet1); err != nil { + return fmt.Errorf("update parameter boolSet1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("boolSet2") { + if err = ap.setBoolSet2(config.BoolSet2); err != nil { + return fmt.Errorf("update parameter boolSet2 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("boolSet3") { + if err = ap.setBoolSet3(config.BoolSet3); err != nil { + return fmt.Errorf("update parameter boolSet3 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("stringSet1") { + if err = ap.setStringSet1(config.StringSet1); err != nil { + return fmt.Errorf("update parameter stringSet1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("stringSet2") { + if err = ap.setStringSet2(config.StringSet2); err != nil { + return fmt.Errorf("update parameter stringSet2 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("int64set1") { + if err = ap.setInt64set1(config.Int64set1); err != nil { + return fmt.Errorf("update parameter int64set1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("int64set3") { + if err = ap.setInt64set3(config.Int64set3); err != nil { + return fmt.Errorf("update parameter int64set3 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("int64Range1") { + if err = ap.setInt64Range1(config.Int64Range1); err != nil { + return fmt.Errorf("update parameter int64Range1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("float64set1") { + if err = ap.setFloat64set1(config.Float64set1); err != nil { + return fmt.Errorf("update parameter float64set1 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("float64set3") { + if err = ap.setFloat64set3(config.Float64set3); err != nil { + return fmt.Errorf("update parameter float64set3 failed.error:%v", err) + } + } + + if config.getUpdatedFlag("float64Range1") { + if err = ap.setFloat64Range1(config.Float64Range1); err != nil { + return fmt.Errorf("update parameter float64Range1 failed.error:%v", err) + } + } + + return nil +} + +/** +Load configuration from file into configuration. +Then update items into AllParameters +*/ +func LoadconfigurationFromFile(filename string, params *AllParameters) error { + config := &configuration{} + if err := config.LoadConfigurationFromFile(filename); err != nil { + return err + } + + if err := params.UpdateParametersWithConfiguration(config); err != nil { + return err + } + return nil +} diff --git a/pkg/config/test/parameters_test.go b/pkg/config/test/parameters_test.go new file mode 100644 index 0000000000000000000000000000000000000000..090c2599ddc5c3406ec288247dca84ee99f0ae08 --- /dev/null +++ b/pkg/config/test/parameters_test.go @@ -0,0 +1,159 @@ +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "sync" + "testing" +) + +func TestAllParameters_LoadInitialValues(t *testing.T) { + ap := &AllParameters{} + if err := ap.LoadInitialValues(); err != nil { + t.Errorf("LoadInitialValues failed. error:%v", err) + } +} + +func isconfigurationEqual(c1, c2 configuration) bool { + + if c1.BoolSet1 != c2.BoolSet1 { + return false + } + + if c1.BoolSet2 != c2.BoolSet2 { + return false + } + + if c1.BoolSet3 != c2.BoolSet3 { + return false + } + + if c1.StringSet1 != c2.StringSet1 { + return false + } + + if c1.StringSet2 != c2.StringSet2 { + return false + } + + if c1.Int64set1 != c2.Int64set1 { + return false + } + + if c1.Int64set3 != c2.Int64set3 { + return false + } + + if c1.Int64Range1 != c2.Int64Range1 { + return false + } + + if c1.Float64set1 != c2.Float64set1 { + return false + } + + if c1.Float64set3 != c2.Float64set3 { + return false + } + + if c1.Float64Range1 != c2.Float64Range1 { + return false + } + + return true +} + +func Test_configuration_LoadConfigurationFromString(t *testing.T) { + t1 := ` + +boolSet1=true + +boolSet2=false + +boolSet3= false + +stringSet1= "ss1" + +stringSet2= "" + +int64set1=1 + + + +int64set3= 0 + +int64Range1=1000 + +float64set1=1.0 + + + +float64set3= 0.0 + +float64Range1=1000.01 + +` + t1_config := configuration{ + rwlock: sync.RWMutex{}, + + BoolSet1: true, + + BoolSet2: false, + + BoolSet3: false, + + StringSet1: "ss1", + + StringSet2: "", + + Int64set1: 1, + + Int64set3: 0, + + Int64Range1: 1000, + + Float64set1: 1.0, + + Float64set3: 0.0, + + Float64Range1: 1000.01, + + name2updatedFlags: nil, + } + + type args struct { + input string + config configuration + } + tests := []struct { + name string + args args + wantErr bool + wantErr2 bool + wantErr3 bool + }{ + {"t1", args{t1, t1_config}, false, false, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ap := &AllParameters{} + if err := ap.LoadInitialValues(); err != nil { + t.Errorf("LoadInitialValues failed.error %v", err) + } + config := &configuration{} + if err := config.LoadConfigurationFromString(tt.args.input); (err != nil) != tt.wantErr { + t.Errorf("LoadConfigurationFromString() error = %v, wantErr %v", err, tt.wantErr) + } else if err != nil { + return + } + + if err := ap.UpdateParametersWithConfiguration(config); (err != nil) != tt.wantErr2 { + t.Errorf("UpdateParametersWithConfiguration failed. error:%v", err) + } + + if (isconfigurationEqual(*config, tt.args.config) != true) != tt.wantErr3 { + t.Errorf("Configuration are not equal. %v vs %v ", *config, tt.args.config) + return + } + }) + } +} diff --git a/pkg/config/test/varconfig.toml b/pkg/config/test/varconfig.toml new file mode 100644 index 0000000000000000000000000000000000000000..d520ee404abc67cd664d6cfe024387369b5d9ced --- /dev/null +++ b/pkg/config/test/varconfig.toml @@ -0,0 +1,87 @@ + +# Code generated by tool; DO NOT EDIT. + + + +# Name: autoload +# Scope: [global] +# Access: [file] +# DataType: bool +# DomainType: set +# Values: [] +# Comment: autoload something +# UpdateMode: dynamic + autoload= false + + + +# Name: rootname +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [root] +# Comment: root name +# UpdateMode: dynamic + rootname= "root" + + + +# Name: rootpassword +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [] +# Comment: root password +# UpdateMode: dynamic + rootpassword= "" + + + +# Name: dumpuser +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [dump] +# Comment: dump user name +# UpdateMode: dynamic + dumpuser= "dump" + + + +# Name: dumppassword +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [111] +# Comment: dump user password +# UpdateMode: dynamic + dumppassword= "111" + + + +# Name: port +# Scope: [global] +# Access: [file] +# DataType: int64 +# DomainType: set +# Values: [9000] +# Comment: port +# UpdateMode: dynamic + port=9000 + + + +# Name: ip +# Scope: [global] +# Access: [file] +# DataType: string +# DomainType: set +# Values: [localhost 127.0.0.1] +# Comment: listening ip +# UpdateMode: dynamic + ip= "localhost" + diff --git a/pkg/config/test/variables.go b/pkg/config/test/variables.go new file mode 100644 index 0000000000000000000000000000000000000000..c7343b74b4eb28525f5a31ab2daf89745471cd54 --- /dev/null +++ b/pkg/config/test/variables.go @@ -0,0 +1,800 @@ +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "fmt" + "github.com/BurntSushi/toml" + "sync" +) + +//all parameters in the system +type Variables struct { + //read and write lock + rwlock sync.RWMutex + + /** + Name: autoload + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [] + Comment: autoload something + UpdateMode: dynamic + */ + autoload bool + + /** + Name: rootname + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [root] + Comment: root name + UpdateMode: dynamic + */ + rootname string + + /** + Name: rootpassword + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [] + Comment: root password + UpdateMode: dynamic + */ + rootpassword string + + /** + Name: dumpuser + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [dump] + Comment: dump user name + UpdateMode: dynamic + */ + dumpuser string + + /** + Name: dumppassword + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [111] + Comment: dump user password + UpdateMode: dynamic + */ + dumppassword string + + /** + Name: port + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [9000] + Comment: port + UpdateMode: dynamic + */ + port int64 + + /** + Name: ip + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [localhost 127.0.0.1] + Comment: listening ip + UpdateMode: dynamic + */ + ip string + + //parameter name -> parameter definition string + name2definition map[string]string +} //end Variables + +//all parameters can be set in the configuration file. +type vconfig struct { + //read and write lock + rwlock sync.RWMutex + + /** + Name: autoload + Scope: [global] + Access: [file] + DataType: bool + DomainType: set + Values: [] + Comment: autoload something + UpdateMode: dynamic + */ + Autoload bool `toml:"autoload"` + + /** + Name: rootname + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [root] + Comment: root name + UpdateMode: dynamic + */ + Rootname string `toml:"rootname"` + + /** + Name: rootpassword + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [] + Comment: root password + UpdateMode: dynamic + */ + Rootpassword string `toml:"rootpassword"` + + /** + Name: dumpuser + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [dump] + Comment: dump user name + UpdateMode: dynamic + */ + Dumpuser string `toml:"dumpuser"` + + /** + Name: dumppassword + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [111] + Comment: dump user password + UpdateMode: dynamic + */ + Dumppassword string `toml:"dumppassword"` + + /** + Name: port + Scope: [global] + Access: [file] + DataType: int64 + DomainType: set + Values: [9000] + Comment: port + UpdateMode: dynamic + */ + Port int64 `toml:"port"` + + /** + Name: ip + Scope: [global] + Access: [file] + DataType: string + DomainType: set + Values: [localhost 127.0.0.1] + Comment: listening ip + UpdateMode: dynamic + */ + Ip string `toml:"ip"` + + //parameter name -> updated flag + name2updatedFlags map[string]bool +} //end vconfig + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (ap *Variables) prepareAnything() { + if ap.name2definition == nil { + ap.name2definition = make(map[string]string) + } +} + +/** +set parameter and its string of the definition. +*/ +func (ap *Variables) PrepareDefinition() { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + ap.prepareAnything() + + ap.name2definition["autoload"] = " Name: autoload Scope: [global] Access: [file] DataType: bool DomainType: set Values: [] Comment: autoload something UpdateMode: dynamic " + + ap.name2definition["rootname"] = " Name: rootname Scope: [global] Access: [file] DataType: string DomainType: set Values: [root] Comment: root name UpdateMode: dynamic " + + ap.name2definition["rootpassword"] = " Name: rootpassword Scope: [global] Access: [file] DataType: string DomainType: set Values: [] Comment: root password UpdateMode: dynamic " + + ap.name2definition["dumpuser"] = " Name: dumpuser Scope: [global] Access: [file] DataType: string DomainType: set Values: [dump] Comment: dump user name UpdateMode: dynamic " + + ap.name2definition["dumppassword"] = " Name: dumppassword Scope: [global] Access: [file] DataType: string DomainType: set Values: [111] Comment: dump user password UpdateMode: dynamic " + + ap.name2definition["port"] = " Name: port Scope: [global] Access: [file] DataType: int64 DomainType: set Values: [9000] Comment: port UpdateMode: dynamic " + + ap.name2definition["ip"] = " Name: ip Scope: [global] Access: [file] DataType: string DomainType: set Values: [localhost 127.0.0.1] Comment: listening ip UpdateMode: dynamic " + +} + +/** +get the definition of the parameter. +*/ +func (ap *Variables) GetDefinition(name string) (string, error) { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if p, ok := ap.name2definition[name]; !ok { + return "", fmt.Errorf("there is no parameter %s", name) + } else { + return p, nil + } +} + +/** +check if there is the parameter +*/ +func (ap *Variables) HasParameter(name string) bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + ap.prepareAnything() + if _, ok := ap.name2definition[name]; !ok { + return false + } else { + return true + } +} + +/** +Load the initial values of all parameters. +*/ +func (ap *Variables) LoadInitialValues() error { + ap.PrepareDefinition() + var err error + + autoloadchoices := []bool{} + if len(autoloadchoices) != 0 { + if err = ap.setAutoload(autoloadchoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Autoload", err) + } + } else { + + if err = ap.setAutoload(false); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Autoload", err) + } + + } + + rootnamechoices := []string{ + + "root", + } + if len(rootnamechoices) != 0 { + if err = ap.setRootname(rootnamechoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Rootname", err) + } + } else { + //empty string + if err = ap.setRootname(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Rootname", err) + } + } + + rootpasswordchoices := []string{ + + "", + } + if len(rootpasswordchoices) != 0 { + if err = ap.setRootpassword(rootpasswordchoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Rootpassword", err) + } + } else { + //empty string + if err = ap.setRootpassword(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Rootpassword", err) + } + } + + dumpuserchoices := []string{ + + "dump", + } + if len(dumpuserchoices) != 0 { + if err = ap.setDumpuser(dumpuserchoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Dumpuser", err) + } + } else { + //empty string + if err = ap.setDumpuser(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Dumpuser", err) + } + } + + dumppasswordchoices := []string{ + + "111", + } + if len(dumppasswordchoices) != 0 { + if err = ap.setDumppassword(dumppasswordchoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Dumppassword", err) + } + } else { + //empty string + if err = ap.setDumppassword(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Dumppassword", err) + } + } + + portchoices := []int64{ + + 9000, + } + if len(portchoices) != 0 { + if err = ap.setPort(portchoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Port", err) + } + } else { + + if err = ap.setPort(0); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Port", err) + } + + } + + ipchoices := []string{ + + "localhost", + + "127.0.0.1", + } + if len(ipchoices) != 0 { + if err = ap.setIp(ipchoices[0]); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Ip", err) + } + } else { + //empty string + if err = ap.setIp(""); err != nil { + return fmt.Errorf("set%s failed.error:%v", "Ip", err) + } + } + + return nil +} + +/** +Get the value of the parameter autoload +*/ +func (ap *Variables) GetAutoload() bool { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.autoload +} + +/** +Get the value of the parameter rootname +*/ +func (ap *Variables) GetRootname() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.rootname +} + +/** +Get the value of the parameter rootpassword +*/ +func (ap *Variables) GetRootpassword() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.rootpassword +} + +/** +Get the value of the parameter dumpuser +*/ +func (ap *Variables) GetDumpuser() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.dumpuser +} + +/** +Get the value of the parameter dumppassword +*/ +func (ap *Variables) GetDumppassword() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.dumppassword +} + +/** +Get the value of the parameter port +*/ +func (ap *Variables) GetPort() int64 { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.port +} + +/** +Get the value of the parameter ip +*/ +func (ap *Variables) GetIp() string { + ap.rwlock.RLock() + defer ap.rwlock.RUnlock() + return ap.ip +} + +/** +Set the value of the parameter autoload +*/ +func (ap *Variables) SetAutoload(value bool) error { + return ap.setAutoload(value) +} + +/** +Set the value of the parameter rootname +*/ +func (ap *Variables) SetRootname(value string) error { + return ap.setRootname(value) +} + +/** +Set the value of the parameter rootpassword +*/ +func (ap *Variables) SetRootpassword(value string) error { + return ap.setRootpassword(value) +} + +/** +Set the value of the parameter dumpuser +*/ +func (ap *Variables) SetDumpuser(value string) error { + return ap.setDumpuser(value) +} + +/** +Set the value of the parameter dumppassword +*/ +func (ap *Variables) SetDumppassword(value string) error { + return ap.setDumppassword(value) +} + +/** +Set the value of the parameter port +*/ +func (ap *Variables) SetPort(value int64) error { + return ap.setPort(value) +} + +/** +Set the value of the parameter ip +*/ +func (ap *Variables) SetIp(value string) error { + return ap.setIp(value) +} + +/** +Set the value of the parameter autoload +*/ +func (ap *Variables) setAutoload(value bool) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []bool{} + if len(choices) != 0 { + if !isInSliceBool(value, choices) { + return fmt.Errorf("setAutoload,the value %t is not in set %v", value, choices) + } + } //else means any bool value: true or false + + ap.autoload = value + return nil +} + +/** +Set the value of the parameter rootname +*/ +func (ap *Variables) setRootname(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "root", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setRootname,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.rootname = value + return nil +} + +/** +Set the value of the parameter rootpassword +*/ +func (ap *Variables) setRootpassword(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setRootpassword,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.rootpassword = value + return nil +} + +/** +Set the value of the parameter dumpuser +*/ +func (ap *Variables) setDumpuser(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "dump", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setDumpuser,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.dumpuser = value + return nil +} + +/** +Set the value of the parameter dumppassword +*/ +func (ap *Variables) setDumppassword(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "111", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setDumppassword,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.dumppassword = value + return nil +} + +/** +Set the value of the parameter port +*/ +func (ap *Variables) setPort(value int64) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []int64{ + + 9000, + } + if len(choices) != 0 { + if !isInSliceInt64(value, choices) { + return fmt.Errorf("setPort,the value %d is not in set %v", value, choices) + } + } //else means any int64 + + ap.port = value + return nil +} + +/** +Set the value of the parameter ip +*/ +func (ap *Variables) setIp(value string) error { + ap.rwlock.Lock() + defer ap.rwlock.Unlock() + + choices := []string{ + + "localhost", + + "127.0.0.1", + } + if len(choices) != 0 { + if !isInSlice(value, choices) { + return fmt.Errorf("setIp,the value %s is not in set %v", value, choices) + } + } //else means any string + + ap.ip = value + return nil +} + +/** +prepare something before anything else. +it is unsafe in multi-thread environment. +*/ +func (config *vconfig) prepareAnything() { + if config.name2updatedFlags == nil { + config.name2updatedFlags = make(map[string]bool) + } +} + +/** +reset update flags of configuration items +*/ +func (config *vconfig) resetUpdatedFlags() { + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + + config.name2updatedFlags["autoload"] = false + + config.name2updatedFlags["rootname"] = false + + config.name2updatedFlags["rootpassword"] = false + + config.name2updatedFlags["dumpuser"] = false + + config.name2updatedFlags["dumppassword"] = false + + config.name2updatedFlags["port"] = false + + config.name2updatedFlags["ip"] = false + +} + +/** +set update flag of configuration item +*/ +func (config *vconfig) setUpdatedFlag(name string, updated bool) { + config.rwlock.Lock() + defer config.rwlock.Unlock() + config.prepareAnything() + config.name2updatedFlags[name] = updated +} + +/** +get update flag of configuration item +*/ +func (config *vconfig) getUpdatedFlag(name string) bool { + config.rwlock.RLock() + defer config.rwlock.RUnlock() + config.prepareAnything() + return config.name2updatedFlags[name] +} + +/** +Load parameters' values in the configuration string. +*/ +func (config *vconfig) LoadConfigurationFromString(input string) error { + config.resetUpdatedFlags() + + metadata, err := toml.Decode(input, config) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + for _, k := range metadata.Keys() { + config.setUpdatedFlag(k[0], true) + } + + return nil +} + +/** +Load parameters' values in the configuration file. +*/ +func (config *vconfig) LoadConfigurationFromFile(fname string) error { + config.resetUpdatedFlags() + + metadata, err := toml.DecodeFile(fname, config) + if err != nil { + return err + } else if failed := metadata.Undecoded(); len(failed) > 0 { + var failedItems []string + for _, item := range failed { + failedItems = append(failedItems, item.String()) + } + return fmt.Errorf("decode failed %s. error:%v", failedItems, err) + } + + for _, k := range metadata.Keys() { + config.setUpdatedFlag(k[0], true) + } + + return nil +} + +/** +Update parameters' values with configuration. +*/ +func (ap *Variables) UpdateParametersWithConfiguration(config *vconfig) error { + var err error + + if config.getUpdatedFlag("autoload") { + if err = ap.setAutoload(config.Autoload); err != nil { + return fmt.Errorf("update parameter autoload failed.error:%v", err) + } + } + + if config.getUpdatedFlag("rootname") { + if err = ap.setRootname(config.Rootname); err != nil { + return fmt.Errorf("update parameter rootname failed.error:%v", err) + } + } + + if config.getUpdatedFlag("rootpassword") { + if err = ap.setRootpassword(config.Rootpassword); err != nil { + return fmt.Errorf("update parameter rootpassword failed.error:%v", err) + } + } + + if config.getUpdatedFlag("dumpuser") { + if err = ap.setDumpuser(config.Dumpuser); err != nil { + return fmt.Errorf("update parameter dumpuser failed.error:%v", err) + } + } + + if config.getUpdatedFlag("dumppassword") { + if err = ap.setDumppassword(config.Dumppassword); err != nil { + return fmt.Errorf("update parameter dumppassword failed.error:%v", err) + } + } + + if config.getUpdatedFlag("port") { + if err = ap.setPort(config.Port); err != nil { + return fmt.Errorf("update parameter port failed.error:%v", err) + } + } + + if config.getUpdatedFlag("ip") { + if err = ap.setIp(config.Ip); err != nil { + return fmt.Errorf("update parameter ip failed.error:%v", err) + } + } + + return nil +} + +/** +Load configuration from file into vconfig. +Then update items into Variables +*/ +func LoadvconfigFromFile(filename string, params *Variables) error { + config := &vconfig{} + if err := config.LoadConfigurationFromFile(filename); err != nil { + return err + } + + if err := params.UpdateParametersWithConfiguration(config); err != nil { + return err + } + return nil +} diff --git a/pkg/config/test/variables_test.go b/pkg/config/test/variables_test.go new file mode 100644 index 0000000000000000000000000000000000000000..d6b3236b11128d74ce83cc34fe2e564e42461eed --- /dev/null +++ b/pkg/config/test/variables_test.go @@ -0,0 +1,123 @@ +// Code generated by tool; DO NOT EDIT. +package config + +import ( + "sync" + "testing" +) + +func TestVariables_LoadInitialValues(t *testing.T) { + ap := &Variables{} + if err := ap.LoadInitialValues(); err != nil { + t.Errorf("LoadInitialValues failed. error:%v", err) + } +} + +func isvconfigEqual(c1, c2 vconfig) bool { + + if c1.Autoload != c2.Autoload { + return false + } + + if c1.Rootname != c2.Rootname { + return false + } + + if c1.Rootpassword != c2.Rootpassword { + return false + } + + if c1.Dumpuser != c2.Dumpuser { + return false + } + + if c1.Dumppassword != c2.Dumppassword { + return false + } + + if c1.Port != c2.Port { + return false + } + + if c1.Ip != c2.Ip { + return false + } + + return true +} + +func Test_vconfig_LoadConfigurationFromString(t *testing.T) { + t1 := ` + +autoload= false + +rootname= "root" + +rootpassword= "" + +dumpuser= "dump" + +dumppassword= "111" + +port=9000 + +ip= "localhost" + +` + t1_config := vconfig{ + rwlock: sync.RWMutex{}, + + Autoload: false, + + Rootname: "root", + + Rootpassword: "", + + Dumpuser: "dump", + + Dumppassword: "111", + + Port: 9000, + + Ip: "localhost", + + name2updatedFlags: nil, + } + + type args struct { + input string + config vconfig + } + tests := []struct { + name string + args args + wantErr bool + wantErr2 bool + wantErr3 bool + }{ + {"t1", args{t1, t1_config}, false, false, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ap := &Variables{} + if err := ap.LoadInitialValues(); err != nil { + t.Errorf("LoadInitialValues failed.error %v", err) + } + config := &vconfig{} + if err := config.LoadConfigurationFromString(tt.args.input); (err != nil) != tt.wantErr { + t.Errorf("LoadConfigurationFromString() error = %v, wantErr %v", err, tt.wantErr) + } else if err != nil { + return + } + + if err := ap.UpdateParametersWithConfiguration(config); (err != nil) != tt.wantErr2 { + t.Errorf("UpdateParametersWithConfiguration failed. error:%v", err) + } + + if (isvconfigEqual(*config, tt.args.config) != true) != tt.wantErr3 { + t.Errorf("Configuration are not equal. %v vs %v ", *config, tt.args.config) + return + } + }) + } +} diff --git a/pkg/server/profiler.go b/pkg/server/profiler.go new file mode 100644 index 0000000000000000000000000000000000000000..45662078e63d514d618bcf6a86401c32452c3c40 --- /dev/null +++ b/pkg/server/profiler.go @@ -0,0 +1,53 @@ +package server + +/** +phase statistics + */ +type PhaseProfiler interface { + /** + start the statistics for the phase. + name: the name of the phase + */ + StartPhase(name string) + + /** + stop the statistics for the phase + */ + EndPhase() + + // ToString convert the phase info into the string + ToString()string +} + +//OperatorProfiler : operator statistics +type OperatorProfiler interface { + //start the statistics for the operator + StartOperator(operator interface{}) + + //end the statistics for the operator + EndOperator() + + //add the operator into the profiler + AddOperator(operator interface{}) + + //convert the operator info into the string + ToString()string +} + +//query statistics +type QueryProfiler interface { + //start the statistics for the query + StartQuery(string) + + //stop the statistics for the query + EndQuery() + + //generate the statistics tree from the physical plan + InitWithPlan() + + //add OperatorProfiler information into the query profiler + AddOperatorProfiler(OperatorProfiler) + + //convert the profiler into the string + ToString() +} \ No newline at end of file diff --git a/pkg/sql/tree/accept.go b/pkg/sql/tree/accept.go new file mode 100644 index 0000000000000000000000000000000000000000..46f6d30af34ee0f09d9a7a43d60151fd9714d296 --- /dev/null +++ b/pkg/sql/tree/accept.go @@ -0,0 +1,8 @@ +package tree + +//Visitor Design Pattern +//Visitor visits the node or sub nodes +type Visitor interface { + Enter(Expr)(bool,Expr) + Exit(Expr)(Expr) +} \ No newline at end of file diff --git a/pkg/sql/tree/constant.go b/pkg/sql/tree/constant.go new file mode 100644 index 0000000000000000000000000000000000000000..8d2a248cf1ea63ace4c881ed3cd6a6f2d2562315 --- /dev/null +++ b/pkg/sql/tree/constant.go @@ -0,0 +1,32 @@ +package tree + +import "go/constant" + +//the AST for literals like string,numeric,bool and etc. +type Constant interface { + Expr +} + +//the AST for the constant numeric value. +type NumVal struct { + Constant + value constant.Value + + // negative is the sign label + negative bool + + // origString is the "original" string literals that should remain sign-less. + origString string + + //converted result + resInt int64 + resFloat float64 +} + +func (n *NumVal) String() string { + return n.origString +} + +func NewNumVal(value constant.Value, origString string, negative bool) *NumVal { + return &NumVal{value: value, origString: origString, negative: negative} +} \ No newline at end of file diff --git a/pkg/sql/tree/expr.go b/pkg/sql/tree/expr.go new file mode 100644 index 0000000000000000000000000000000000000000..f0c05c79601f4c4acd9982eeb24b80fd09a16840 --- /dev/null +++ b/pkg/sql/tree/expr.go @@ -0,0 +1,401 @@ +package tree + +import ( + "fmt" +) + +//AST for the expression +type Expr interface { + fmt.Stringer + NodePrinter + + //Visitor Design Pattern + //Accept the visitor to access the node. + Accept(Visitor) Expr +} + +type exprImpl struct { +} + +func (ei *exprImpl) String() string { + return "" +} + +func (ei *exprImpl) Print(ctx *PrintCtx) { +} + +func (ei *exprImpl) Accept(_ Visitor) Expr { + return ei +} + +//Binary Operator +type BinaryOp int + +const ( + PLUS BinaryOp = iota + MINUS + MULTI + DIV // / + INTEGER_DIV // + BIT_OR // | + BIT_AND // & + BIT_XOR // ^ + LEFT_SHIFT // << + RIGHT_SHIFT // >> + MOD // % +) + +var binaryOpName = []string{ + "+", + "-", + "*", + "/", +} + +//binary expression +type BinaryExpr struct { + exprImpl + + //operator + Op BinaryOp + + //left expression + Left Expr + + //right expression + Right Expr +} + +func NewBinaryExpr(op BinaryOp, left Expr, right Expr) *BinaryExpr { + return &BinaryExpr{ + Op: op, + Left: left, + Right: right, + } +} + +//unary expression +type UnaryOp int + +const ( + //- + UNARY_MINUS UnaryOp = iota + //+ + UNARY_PLUS + //~ + UNARY_TILDE + //! + UNARY_MARK +) + +var unaryOpName = []string{ + "-", + "+", + "~", + "!", +} + +//unary expression +type UnaryExpr struct { + exprImpl + + //operator + Op UnaryOp + + //expression + Expr Expr +} + +func NewUnaryExpr(op UnaryOp, expr Expr) *UnaryExpr { + return &UnaryExpr{ + Op: op, + Expr: expr, + } +} + +//comparion operation +type ComparisonOp int + +const ( + EQUAL ComparisonOp = iota // = + LESS_THAN // < + LESS_THAN_EQUAL // <= + GREAT_THAN // > + GREAT_THAN_EQUAL // >= + NOT_EQUAL // <>, != + IN // IN + NOT_IN // NOT IN + LIKE // LIKE + NOT_LIKE // NOT LIKE + REG_MATCH // REG_MATCH + NOT_REG_MATCH // NOT REG_MATCH + + //reference: https://dev.mysql.com/doc/refman/8.0/en/all-subqueries.html + //subquery with ANY,SOME,ALL + //operand comparison_operator [ANY | SOME | ALL] (subquery) + ANY + SOME + ALL +) + +var comparionName = []string{ + "=", + "<", + "<=", + ">", + ">=", + "!=", + "IN", + "NOT IN", + "LIKE", + "NOT LIKE", +} + +type ComparisonExpr struct { + exprImpl + Op ComparisonOp + + //ANY SOME ALL with subquery + SubOp ComparisonOp + Left Expr + Right Expr +} + +func NewComparisonExpr(op ComparisonOp, l, r Expr) *ComparisonExpr { + return &ComparisonExpr{ + Op: op, + SubOp: ComparisonOp(0), + Left: l, + Right: r, + } +} + +func NewComparisonExprWithSubop(op, subop ComparisonOp, l, r Expr) *ComparisonExpr { + return &ComparisonExpr{ + Op: op, + SubOp: subop, + Left: l, + Right: r, + } +} + +//and expression +type AndExpr struct { + exprImpl + Left, Right Expr +} + +func NewAndExpr(l, r Expr) *AndExpr { + return &AndExpr{ + Left: l, + Right: r, + } +} + +//xor expression +type XorExpr struct { + exprImpl + Left, Right Expr +} + +func NewXorExpr(l, r Expr) *XorExpr { + return &XorExpr{ + Left: l, + Right: r, + } +} + +//or expression +type OrExpr struct { + exprImpl + Left, Right Expr +} + +func NewOrExpr(l, r Expr) *OrExpr { + return &OrExpr{ + Left: l, + Right: r, + } +} + +//not expression +type NotExpr struct { + exprImpl + Expr Expr +} + +func NewNotExpr(e Expr) *NotExpr { + return &NotExpr{ + Expr: e, + } +} + +//is null expression +type IsNullExpr struct { + exprImpl + Expr Expr +} + +func NewIsNullExpr(e Expr) *IsNullExpr { + return &IsNullExpr{ + Expr: e, + } +} + +//is not null expression +type IsNotNullExpr struct { + exprImpl + Expr Expr +} + +func NewIsNotNullExpr(e Expr) *IsNotNullExpr { + return &IsNotNullExpr{ + Expr: e, + } +} + +//subquery interface +type SubqueryExpr interface { + Expr +} + +//subquery +type Subquery struct { + SubqueryExpr + + Select SelectStatement + Exists bool +} + +func NewSubquery(s SelectStatement, e bool) *Subquery { + return &Subquery{ + Select: s, + Exists: e, + } +} + +//a list of expression. +type Exprs []Expr + +//ast fir the list of expression +type ExprList struct { + exprImpl + Exprs Exprs +} + +//the parenthesized expression. +type ParenExpr struct { + exprImpl + Expr Expr +} + +func NewParenExpr(e Expr) *ParenExpr { + return &ParenExpr{ + Expr: e, + } +} + +type funcType int + +const ( + _ funcType = iota + FUNC_TYPE_DISTINCT + FUNC_TYPE_ALL +) + +// AggType specifies the type of aggregation. +type AggType int + +const ( + _ AggType = iota + AGG_TYPE_GENERAL +) + +//the common interface to UnresolvedName and QualifiedFunctionName. +type FunctionReference interface { + fmt.Stringer + NodePrinter +} + +var _ FunctionReference = &UnresolvedName{} + +//function reference +type ResolvableFunctionReference struct { + FunctionReference +} + +func FuncName2ResolvableFunctionReference(funcName *UnresolvedName) ResolvableFunctionReference { + return ResolvableFunctionReference{FunctionReference: funcName} +} + +//function call expression +type FuncExpr struct { + exprImpl + Func ResolvableFunctionReference + Type funcType + Exprs Exprs + + //specify the type of aggregation. + AggType AggType + + //aggregations which specify an order. + OrderBy OrderBy +} + +func NewFuncExpr(ft funcType, name *UnresolvedName, e Exprs, order OrderBy) *FuncExpr { + return &FuncExpr{ + Func: FuncName2ResolvableFunctionReference(name), + Type: ft, + Exprs: e, + AggType: AGG_TYPE_GENERAL, + OrderBy: order, + } +} + +//type reference +type ResolvableTypeReference interface { +} + +var _ ResolvableTypeReference = &UnresolvedObjectName{} +var _ ResolvableTypeReference = &T{} + +//the Cast expression +type CastExpr struct { + exprImpl + Expr Expr + Type ResolvableTypeReference +} + +func NewCastExpr(e Expr, t ResolvableTypeReference) *CastExpr { + return &CastExpr{ + Expr: e, + Type: t, + } +} + +//the parenthesized list of expressions. +type Tuple struct { + exprImpl + Exprs Exprs +} + +func NewTuple(e Exprs) *Tuple { + return &Tuple{Exprs: e} +} + +//the BETWEEN or a NOT BETWEEN expression +type RangeCond struct { + exprImpl + Not bool + Left Expr + From, To Expr +} + +func NewRangeCond(n bool, l, f, t Expr) *RangeCond { + return &RangeCond{ + Not: n, + Left: l, + From: f, + To: t, + } +} diff --git a/pkg/sql/tree/identifier.go b/pkg/sql/tree/identifier.go new file mode 100644 index 0000000000000000000000000000000000000000..139f4e35fc00ab24bd1733e4636d7d68cc5cad36 --- /dev/null +++ b/pkg/sql/tree/identifier.go @@ -0,0 +1,89 @@ +package tree + +import "fmt" + +// IdentifierName is referenced in the expression +type IdentifierName interface { + Expr +} + +//sql indentifier +type Identifier string + +// +type UnrestrictedIdentifier string + +//the list of identifiers. +type IdentifierList []Identifier + +type ColumnItem struct { + IdentifierName + + //the name of the column + ColumnName Identifier +} + +//the unresolved qualified name like column name. +type UnresolvedName struct { + exprImpl + //the number of name parts specified, including the star. Always 1 or greater. + NumParts int + + //the name ends with a star. then the first element is empty in the Parts + Star bool + + // Parts are the name components (at most 4: column, table, schema, catalog/db.), in reverse order. + Parts NameParts +} + +//the path in an UnresolvedName. +type NameParts = [4]string + +func NewUnresolvedName(parts ...string)(*UnresolvedName,error){ + l:=len(parts) + if l < 1 || l > 4{ + return nil,fmt.Errorf("the count of name parts among [1,4]") + } + u:= &UnresolvedName{ + NumParts: len(parts), + Star: false, + } + for i:=0 ; i < len(parts);i++{ + u.Parts[i] = parts[l - 1 - i] + } + return u,nil +} + +func NewUnresolvedNameWithStar(parts ...string)(*UnresolvedName,error){ + l:=len(parts) + if l < 1 || l > 3{ + return nil,fmt.Errorf("the count of name parts among [1,3]") + } + u:= &UnresolvedName{ + NumParts: 1+len(parts), + Star: true, + } + u.Parts[0] = "" + for i:=0 ; i < len(parts);i++{ + u.Parts[i+1] = parts[l - 1 - i] + } + return u,nil +} +//variable in the scalar expression +type VarName interface { + Expr +} + +var _ VarName = &UnresolvedName{} +var _ VarName = UnqualifiedStar{} + +//'*' in the scalar expression +type UnqualifiedStar struct{ + VarName +} + +var starName VarName = UnqualifiedStar{} + +func StarExpr()VarName{ + return starName +} diff --git a/pkg/sql/tree/object_name.go b/pkg/sql/tree/object_name.go new file mode 100644 index 0000000000000000000000000000000000000000..519133376041a21883bc89f7c35c4cfa9dbcab08 --- /dev/null +++ b/pkg/sql/tree/object_name.go @@ -0,0 +1,63 @@ +package tree + +import "fmt" + +//the common interface for qualified object names +type ObjectName interface { + NodePrinter +} + +//the internal type for a qualified object. +type objName struct { + //the path to the object. + ObjectNamePrefix + + //the unqualified name for the object + ObjectName Identifier +} + +//the path prefix of an object name. +type ObjectNamePrefix struct { + CatalogName Identifier + SchemaName Identifier + + //true iff the catalog was explicitly specified + ExplicitCatalog bool + //true iff the schema was explicitly specified + ExplicitSchema bool +} + +//the unresolved qualified name for a database object (table, view, etc) +type UnresolvedObjectName struct { + //the number of name parts; >= 1 + NumParts int + + //At most three components, in reverse order. + //object name, schema, catalog/db. + Parts [3]string +} + +func (u *UnresolvedObjectName) ToTableName() TableName { + return TableName{ + objName: objName{ + ObjectNamePrefix: ObjectNamePrefix{ + SchemaName: Identifier(u.Parts[1]), + CatalogName: Identifier(u.Parts[2]), + ExplicitSchema: u.NumParts >= 2, + ExplicitCatalog: u.NumParts >= 3, + }, + ObjectName: Identifier(u.Parts[0]), + }, + } +} + +func NewUnresolvedObjectName(num int,parts [3]string)(*UnresolvedObjectName,error){ + if num < 1 || num > 3{ + return nil,fmt.Errorf("invalid number of parts.") + } + return &UnresolvedObjectName{ + NumParts: num, + Parts: parts, + },nil +} + diff --git a/pkg/sql/tree/parser.go b/pkg/sql/tree/parser.go new file mode 100644 index 0000000000000000000000000000000000000000..738e8ccadcecfc38f278e91e9db49851a4139714 --- /dev/null +++ b/pkg/sql/tree/parser.go @@ -0,0 +1,32 @@ +package tree + +import ( + "fmt" + "github.com/pingcap/parser" + "github.com/pingcap/parser/ast" +) + +type Parser struct { + p *parser.Parser +} + +func NewParser() *Parser { + return &Parser{p: parser.New()} +} + +func (p *Parser) Parse(sql string) ([]Statement, error) { + stmtNodes, _, err := p.p.Parse(sql, "", "") + if err != nil { + return nil, fmt.Errorf("parser parse failed.error:%v", err) + } + + var tree_stmt []Statement = make([]Statement, len(stmtNodes)) + for i, stmt := range stmtNodes { + if ss, ok := stmt.(*ast.SelectStmt); !ok { + return nil, fmt.Errorf("parser parse failed.error:%v", err) + } else { + tree_stmt[i] = transformSelectStmtToSelect(ss) + } + } + return tree_stmt, nil +} diff --git a/pkg/sql/tree/parser_test.go b/pkg/sql/tree/parser_test.go new file mode 100644 index 0000000000000000000000000000000000000000..315fd2f563357128682742e299cc82a6a89312ea --- /dev/null +++ b/pkg/sql/tree/parser_test.go @@ -0,0 +1,45 @@ +package tree + +import ( + "reflect" + "testing" +) + +func TestParse(t *testing.T) { + type args struct { + sql string + } + //_,s :=gen_transform_t15() + //sql :=`SELECT u.a,(SELECT t.a FROM sa.t,u) + // from u,(SELECT t.a,u.a FROM sa.t,u where t.a = u.a) + // where (u.a,u.b,u.c) in (SELECT t.a,u.a,t.b * u.b tubb + // FROM sa.t join u on t.c = u.c or t.d != u.d + // join v on u.a != v.a + // where t.a = u.a and t.b > u.b + // group by t.a,u.a,(t.b+u.b+v.b) + // having t.a = 'jj' and v.c > 1000 + // order by t.a asc,u.a desc,v.d asc,tubb + // limit 100,2000);` + + tests := []struct { + name string + args args + want []Statement + wantErr bool + }{} + + p := NewParser() + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := p.Parse(tt.args.sql) + if (err != nil) != tt.wantErr { + t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Parse() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/sql/tree/print.go b/pkg/sql/tree/print.go new file mode 100644 index 0000000000000000000000000000000000000000..dcfeb782776c6def9dae20aefa05b01bb145e70e --- /dev/null +++ b/pkg/sql/tree/print.go @@ -0,0 +1,13 @@ +package tree + +import "bytes" + +// PrintCtx contains formatted text of the node. +type PrintCtx struct { + bytes.Buffer +} + +// NodePrinter for formatted output of the node. +type NodePrinter interface { + Print(ctx *PrintCtx) +} \ No newline at end of file diff --git a/pkg/sql/tree/readme.md b/pkg/sql/tree/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..22d185cff4f74118974c43484f67e519579e483e --- /dev/null +++ b/pkg/sql/tree/readme.md @@ -0,0 +1,22 @@ +Until now, I have only implemented the transformers in SelectStmt. + +# usage +Parser is in parser.go + +``` +p := NewParser() +ast, err := p.Parse(sql) +``` + +# unsupported expression transformers that will be implemented in the future + +CaseExpr{} -> CaseExpr +DefaultExpr{} -> ColumnItem +PositionExpr{} -> OrderBy / GroupBy position + +ValuesExpr{} -> ValuesClause keyword: VALUES +VariableExpr{} -> system / session variables + -> DDate / DTime / DTimestamp + +# supported expression transformers +All transformers are in the file transformer.go diff --git a/pkg/sql/tree/select.go b/pkg/sql/tree/select.go new file mode 100644 index 0000000000000000000000000000000000000000..b4bdfdce644560601a185d948d8b88837ce8dc08 --- /dev/null +++ b/pkg/sql/tree/select.go @@ -0,0 +1,221 @@ +package tree + +type SelectStatement interface { + Statement +} + +//the SelectStatement with an ORDER and/or LIMIT. +type Select struct { + statementImpl + Select SelectStatement + OrderBy OrderBy + Limit *Limit +} + +// OrderBy represents an ORDER BY clause. +type OrderBy []*Order + +//the ordering expression. +type Order struct { + Expr Expr + Direction Direction + //without order + NullOrder bool +} + +func NewOrder(e Expr, d Direction, o bool) *Order { + return &Order{ + Expr: e, + Direction: d, + NullOrder: o, + } +} + +// Direction for ordering results. +type Direction int8 + +// Direction values. +const ( + Ascending Direction = iota + Descending +) + +var directionName = []string{ + "ASC", + "DESC", +} + +//the LIMIT clause. +type Limit struct { + Offset, Count Expr +} + +func NewLimit(o, c Expr) *Limit { + return &Limit{ + Offset: o, + Count: c, + } +} + +// the parenthesized SELECT/UNION/VALUES statement. +type ParenSelect struct { + SelectStatement + Select *Select +} + +type SelectClause struct { + SelectStatement + From *From + Distinct bool + Where *Where + Exprs SelectExprs + GroupBy GroupBy + Having *Where +} + +//WHERE or HAVING clause. +type Where struct { + Expr Expr +} + +func NewWhere(e Expr) *Where { + return &Where{Expr: e} +} + +//SELECT expressions. +type SelectExprs []SelectExpr + +//a SELECT expression. +type SelectExpr struct { + Expr Expr + As UnrestrictedIdentifier +} + +//a GROUP BY clause. +type GroupBy []Expr + +const ( + JOIN_TYPE_FULL = "FULL" + JOIN_TYPE_LEFT = "LEFT" + JOIN_TYPE_RIGHT = "RIGHT" + JOIN_TYPE_CROSS = "CROSS" + JOIN_TYPE_INNER = "INNER" +) + +//the table expression +type TableExpr interface { + NodePrinter +} + +type tableExprImpl struct { +} + +func (tei *tableExprImpl) Print(ctx *PrintCtx) {} + +var _ TableExpr = &Subquery{} + +type JoinTableExpr struct { + TableExpr + JoinType string + Left TableExpr + Right TableExpr + Cond JoinCond +} + +func NewJoinTableExpr(jt string, l, r TableExpr, jc JoinCond) *JoinTableExpr { + return &JoinTableExpr{ + JoinType: jt, + Left: l, + Right: r, + Cond: jc, + } +} + +//the join condition. +type JoinCond interface { + NodePrinter +} + +// the NATURAL join condition +type NaturalJoinCond struct { + JoinCond +} + +func NewNaturalJoinCond() *NaturalJoinCond { + return &NaturalJoinCond{} +} + +//the ON condition for join +type OnJoinCond struct { + JoinCond + Expr Expr +} + +func NewOnJoinCond(e Expr) *OnJoinCond { + return &OnJoinCond{Expr: e} +} + +//the USING condition +type UsingJoinCond struct { + JoinCond + Cols IdentifierList +} + +func NewUsingJoinCond(c IdentifierList) *UsingJoinCond { + return &UsingJoinCond{Cols: c} +} + +//the parenthesized TableExpr. +type ParenTableExpr struct { + TableExpr + Expr TableExpr +} + +func NewParenTableExpr(e TableExpr) *ParenTableExpr { + return &ParenTableExpr{Expr: e} +} + +//The alias, optionally with a column list: +// "AS name" or "AS name(col1, col2)". +type AliasClause struct { + NodePrinter + Alias Identifier +} + +//the table expression coupled with an optional alias. +type AliasedTableExpr struct { + TableExpr + Expr TableExpr + As AliasClause +} + +func NewAliasedTableExpr(e TableExpr, a AliasClause) *AliasedTableExpr { + return &AliasedTableExpr{ + Expr: e, + As: a, + } +} + +//the statements as a data source includes the select statement. +type StatementSource struct { + TableExpr + Statement Statement +} + +func NewStatementSource(s Statement) *StatementSource { + return &StatementSource{ + Statement: s, + } +} + +//the list of table expressions. +type TableExprs []TableExpr + +//the FROM clause. +type From struct { + Tables TableExprs +} + +func NewFrom(t TableExprs) *From { + return &From{Tables: t} +} diff --git a/pkg/sql/tree/stmt.go b/pkg/sql/tree/stmt.go new file mode 100644 index 0000000000000000000000000000000000000000..b06aa98dc7bba660155a49d8514994ae3acce5af --- /dev/null +++ b/pkg/sql/tree/stmt.go @@ -0,0 +1,12 @@ +package tree + +import "fmt" + +type Statement interface { + fmt.Stringer + NodePrinter +} + +type statementImpl struct { + Statement +} diff --git a/pkg/sql/tree/table_name.go b/pkg/sql/tree/table_name.go new file mode 100644 index 0000000000000000000000000000000000000000..2497690ce09db4022fd09fcc5ffa97519970e6bd --- /dev/null +++ b/pkg/sql/tree/table_name.go @@ -0,0 +1,17 @@ +package tree + +type TableName struct { + TableExpr + objName +} + +var _ TableExpr = &TableName{} + +func NewTableName(name Identifier,prefix ObjectNamePrefix)*TableName{ + return &TableName{ + objName: objName{ + ObjectName: name, + ObjectNamePrefix:prefix, + }, + } +} \ No newline at end of file diff --git a/pkg/sql/tree/transformer.go b/pkg/sql/tree/transformer.go new file mode 100644 index 0000000000000000000000000000000000000000..f5bcd2f80e030694653c6d91be94b9348a583739 --- /dev/null +++ b/pkg/sql/tree/transformer.go @@ -0,0 +1,841 @@ +package tree + +import ( + "fmt" + "github.com/pingcap/parser/ast" + "github.com/pingcap/parser/mysql" + "github.com/pingcap/parser/opcode" + "github.com/pingcap/parser/test_driver" + "go/constant" +) + +//transform test_driver.ValueExpr::Datum to tree.NumVal +//decimal -> ? +//null -> unknown +func transformDatumToNumVal(datum *test_driver.Datum) *NumVal { + switch datum.Kind() { + case test_driver.KindNull: //go Unknown Value expresses the null value. + return NewNumVal(constant.MakeUnknown(), "", false) + case test_driver.KindInt64: //include mysql true,false + return NewNumVal(constant.MakeInt64(datum.GetInt64()), "", false) + case test_driver.KindUint64: + return NewNumVal(constant.MakeUint64(datum.GetUint64()), "", false) + case test_driver.KindFloat32: + return NewNumVal(constant.MakeFloat64(datum.GetFloat64()), "", false) + case test_driver.KindFloat64: //mysql 1.2E3, 1.2E-3, -1.2E3, -1.2E-3; + return NewNumVal(constant.MakeFloat64(datum.GetFloat64()), "", false) + case test_driver.KindString: + return NewNumVal(constant.MakeString(datum.GetString()), "", false) + case test_driver.KindBytes: + fallthrough + case test_driver.KindBinaryLiteral: + fallthrough + case test_driver.KindMysqlDecimal: //mysql .2, 3.4, -6.78, +9.10 + fallthrough + case test_driver.KindMysqlDuration: + fallthrough + case test_driver.KindMysqlEnum: + fallthrough + case test_driver.KindMysqlBit: + fallthrough + case test_driver.KindMysqlSet: + fallthrough + case test_driver.KindMysqlTime: + fallthrough + case test_driver.KindInterface: + fallthrough + case test_driver.KindMinNotNull: + fallthrough + case test_driver.KindMaxValue: + fallthrough + case test_driver.KindRaw: + fallthrough + case test_driver.KindMysqlJSON: + fallthrough + default: + panic("unsupported datum type") + } +} + +//transform ast.UnaryOperationExpr to tree.UnaryExpr +func transformUnaryOperatorExprToUnaryExpr(uoe *ast.UnaryOperationExpr) *UnaryExpr { + switch uoe.Op { + case opcode.Minus: + e := transformExprNodeToExpr(uoe.V) + return NewUnaryExpr(UNARY_MINUS, e) + case opcode.Plus: + e := transformExprNodeToExpr(uoe.V) + return NewUnaryExpr(UNARY_PLUS, e) + case opcode.BitNeg: //~ + e := transformExprNodeToExpr(uoe.V) + return NewUnaryExpr(UNARY_TILDE, e) + case opcode.Not2: //! + e := transformExprNodeToExpr(uoe.V) + return NewUnaryExpr(UNARY_MARK, e) + + } + panic(fmt.Errorf("unsupported unary expr. op:%s ", uoe.Op.String())) + return nil +} + +//transform ast.UnaryOperationExpr to tree.NotExpr +func transformUnaryOperatorExprToNotExpr(uoe *ast.UnaryOperationExpr) *NotExpr { + switch uoe.Op { + case opcode.Not: //not,! + e := transformExprNodeToExpr(uoe.V) + return NewNotExpr(e) + } + panic(fmt.Errorf("unsupported not expr. op:%s ", uoe.Op.String())) + return nil +} + +//transform ast.BinaryOperationExpr to tree.BinaryExpr +func transformBinaryOperationExprToBinaryExpr(boe *ast.BinaryOperationExpr) *BinaryExpr { + switch boe.Op { + //math operation + case opcode.Plus: + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(PLUS, l, r) + case opcode.Minus: + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(MINUS, l, r) + case opcode.Mul: + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(MULTI, l, r) + case opcode.Div: // / + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(DIV, l, r) + case opcode.Mod: //% + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(MOD, l, r) + case opcode.IntDiv: // integer division + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(INTEGER_DIV, l, r) + //bit wise operation + case opcode.Or: //bit or | + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(BIT_OR, l, r) + case opcode.And: //bit and & + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(BIT_AND, l, r) + case opcode.Xor: //bit xor ^ + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(BIT_XOR, l, r) + case opcode.LeftShift: //<< + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(LEFT_SHIFT, l, r) + case opcode.RightShift: //>> + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewBinaryExpr(RIGHT_SHIFT, l, r) + //logic operation + } + panic(fmt.Errorf("unsupported binary expr. op:%s ", boe.Op.String())) + return nil +} + +//transform ast.BinaryOperationExpr to tree.ComparisonExpr +func transformBinaryOperationExprToComparisonExpr(boe *ast.BinaryOperationExpr) *ComparisonExpr { + switch boe.Op { + //comparison operation + case opcode.EQ: // = + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewComparisonExpr(EQUAL, l, r) + case opcode.LT: // < + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewComparisonExpr(LESS_THAN, l, r) + case opcode.LE: // <= + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewComparisonExpr(LESS_THAN_EQUAL, l, r) + case opcode.GT: // > + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewComparisonExpr(GREAT_THAN, l, r) + case opcode.GE: // >= + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewComparisonExpr(GREAT_THAN_EQUAL, l, r) + case opcode.NE: // <>,!= + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewComparisonExpr(NOT_EQUAL, l, r) + } + panic(fmt.Errorf("unsupported comparison expr. op:%s ", boe.Op.String())) + return nil +} + +//transform ast.BinaryOperationExpr to tree.AndExpr +func transformBinaryOperationExprToAndExpr(boe *ast.BinaryOperationExpr) *AndExpr { + switch boe.Op { + //logic operation + case opcode.LogicAnd: // and,&& + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewAndExpr(l, r) + } + panic(fmt.Errorf("unsupported and expr. op:%s ", boe.Op.String())) + return nil +} + +//transform ast.BinaryOperationExpr to tree.OrExpr +func transformBinaryOperationExprToOrExpr(boe *ast.BinaryOperationExpr) *OrExpr { + switch boe.Op { + //logic operation + case opcode.LogicOr: // or,|| + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewOrExpr(l, r) + } + panic(fmt.Errorf("unsupported or expr. op:%s ", boe.Op.String())) + return nil +} + +//transform ast.BinaryOperationExpr to tree.XorExpr +func transformBinaryOperationExprToXorExpr(boe *ast.BinaryOperationExpr) *XorExpr { + switch boe.Op { + //logic operation + case opcode.LogicXor: // xor + l := transformExprNodeToExpr(boe.L) + r := transformExprNodeToExpr(boe.R) + return NewXorExpr(l, r) + } + panic(fmt.Errorf("unsupported xor expr. op:%s ", boe.Op.String())) + return nil +} + +//transform ast.IsNullExpr to tree.IsNullExpr +func transformIsNullExprToIsNullExpr(ine *ast.IsNullExpr) *IsNullExpr { + if !ine.Not { + e := transformExprNodeToExpr(ine.Expr) + return NewIsNullExpr(e) + } + panic(fmt.Errorf("unsupported is null expr. %v ", ine)) + return nil +} + +//transform ast.IsNotNullExpr to tree.IsNotNullExpr +func transformIsNullExprToIsNotNullExpr(ine *ast.IsNullExpr) *IsNotNullExpr { + if ine.Not { + e := transformExprNodeToExpr(ine.Expr) + return NewIsNotNullExpr(e) + } + panic(fmt.Errorf("unsupported is not null expr. %v ", ine)) + return nil +} + +//transform ast.PatternInExpr (in expression) to tree.ComparisonExpr.In +func transformPatternInExprToComparisonExprIn(pie *ast.PatternInExpr) *ComparisonExpr { + e1 := transformExprNodeToExpr(pie.Expr) + var e2 Expr + var op ComparisonOp + if len(pie.List) != 0 { + // => ExprList + l := &ExprList{ + Exprs: make([]Expr, len(pie.List)), + } + for i, x := range pie.List { + l.Exprs[i] = transformExprNodeToExpr(x) + } + e2 = l + } else if pie.Sel != nil { + e2 = transformExprNodeToExpr(pie.Sel) + } + + if pie.Not { + op = NOT_IN + } else { + op = IN + } + + return NewComparisonExpr(op, e1, e2) +} + +//transform ast.PatternLikeExpr (in expression) to tree.ComparisonExpr.LIKE +func transformPatternLikeExprToComparisonExprIn(ple *ast.PatternLikeExpr) *ComparisonExpr { + e1 := transformExprNodeToExpr(ple.Expr) + e2 := transformExprNodeToExpr(ple.Pattern) + //TODO:escape + + var op ComparisonOp + + if ple.Not { + op = NOT_LIKE + } else { + op = LIKE + } + + return NewComparisonExpr(op, e1, e2) +} + +//transform ast.PatternRegexpExpr (in expression) to tree.ComparisonExpr.REG_MATCH +func transformPatternRegexpExprToComparisonExprIn(pre *ast.PatternRegexpExpr) *ComparisonExpr { + e1 := transformExprNodeToExpr(pre.Expr) + e2 := transformExprNodeToExpr(pre.Pattern) + + var op ComparisonOp + + if pre.Not { + op = NOT_REG_MATCH + } else { + op = REG_MATCH + } + + return NewComparisonExpr(op, e1, e2) +} + +//transform ast.ResultSetNode to tree.SelectStatement +func transformResultSetNodeToSelectStatement(rsn ast.ResultSetNode) SelectStatement { + switch n := rsn.(type) { + case *ast.SelectStmt: + return transformSelectStmtToSelectStatement(n) + } + panic(fmt.Errorf("unsupported resultSetNode")) + return nil +} + +//transform ast.SubqueryExpr to tree.Subquery +func transformSubqueryExprToSubquery(se *ast.SubqueryExpr) *Subquery { + e := transformResultSetNodeToSelectStatement(se.Query) + return NewSubquery(e, se.Exists) +} + +//transform ast.ExistsSubqueryExpr to tree.Subquery +func transformExistsSubqueryExprToSubquery(ese *ast.ExistsSubqueryExpr) *Subquery { + e := transformExprNodeToExpr(ese.Sel) + return NewSubquery(e, ese.Not) +} + +//transform ast.CompareSubqueryExpr to tree.ComparisonExpr.SubOp +func transformCompareSubqueryExprToSubquery(cse *ast.CompareSubqueryExpr) *ComparisonExpr { + l := transformExprNodeToExpr(cse.L) + r := transformExprNodeToExpr(cse.R) + var subop ComparisonOp + + if cse.All { + subop = ALL + } else { + subop = ANY + } + + switch cse.Op { + //comparison operation + case opcode.EQ: // = + return NewComparisonExprWithSubop(EQUAL, subop, l, r) + case opcode.LT: // < + return NewComparisonExprWithSubop(LESS_THAN, subop, l, r) + case opcode.LE: // <= + return NewComparisonExprWithSubop(LESS_THAN_EQUAL, subop, l, r) + case opcode.GT: // > + return NewComparisonExprWithSubop(GREAT_THAN, subop, l, r) + case opcode.GE: // >= + return NewComparisonExprWithSubop(GREAT_THAN_EQUAL, subop, l, r) + case opcode.NE: // <>,!= + return NewComparisonExprWithSubop(NOT_EQUAL, subop, l, r) + } + panic(fmt.Errorf("unsupported CompareSubqueryExpr expr. op:%s ", cse.Op.String())) + return nil +} + +//transform ast.ParenthesesExpr to tree.ParenExpr +func transformParenthesesExprToParenExpr(pe *ast.ParenthesesExpr) *ParenExpr { + e := transformExprNodeToExpr(pe.Expr) + return NewParenExpr(e) +} + +//transform ast.TableName to tree.TableName +func transformTableNameToTableName(tn *ast.TableName) *TableName { + return NewTableName(Identifier(tn.Name.O), ObjectNamePrefix{ + CatalogName: "", + SchemaName: Identifier(tn.Schema.O), + ExplicitCatalog: false, + ExplicitSchema: len(tn.Schema.O) != 0, + }) +} + +//transform ast.TableSource to tree.AliasedTableExpr +func transformTableSourceToAliasedTableExpr(ts *ast.TableSource) *AliasedTableExpr { + te := transformResultSetNodeToTableExpr(ts.Source) + return NewAliasedTableExpr(te, AliasClause{ + Alias: Identifier(ts.AsName.O), + }) +} + +//transform ast.SelectStmt to tree.StatementSource +func transformSelectStmtToStatementSource(ss *ast.SelectStmt) *StatementSource { + sts := transformSelectStmtToSelectStatement(ss) + return NewStatementSource(sts) +} + +//transform ast.ResultSetNode to tree.TableExpr +func transformResultSetNodeToTableExpr(rsn ast.ResultSetNode) TableExpr { + switch n := rsn.(type) { + case *ast.SubqueryExpr: + return transformSubqueryExprToSubquery(n) + case *ast.Join: + if n.ExplicitParens { + return transformJoinToParenTableExpr(n) + } + return transformJoinToJoinTableExpr(n) + case *ast.TableName: + return transformTableNameToTableName(n) + case *ast.TableSource: + return transformTableSourceToAliasedTableExpr(n) + case *ast.SelectStmt: + return transformSelectStmtToStatementSource(n) + } + panic(fmt.Errorf("unsupported ResultSetNode type:%v ", rsn)) + return nil +} + +//transform []*ast.ColumnName to tree.IdentifierList +func transformColumnNameListToNameList(cn []*ast.ColumnName) IdentifierList { + var l IdentifierList + for _, x := range cn { + l = append(l, Identifier(x.Name.O)) + } + return l +} + +/* +transform ast.Join to tree.JoinTableExpr +This is core of transformation from ast.TableRefsClause to tree.From + +FROM: https://dev.mysql.com/doc/refman/8.0/en/join.html +In MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents (they can replace each other). +In standard SQL, they are not equivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used otherwise. + +INNER JOIN is used with the ON condition. +NATURAL JOIN has implicit ON condition - columns with same names in both tables. +STRAIGHT JOIN defines the order among the tables from the left to the right. +*/ +func transformJoinToJoinTableExpr(j *ast.Join) *JoinTableExpr { + var t string + var joinCon JoinCond + + switch j.Tp { + case ast.CrossJoin: + t = JOIN_TYPE_CROSS + case ast.LeftJoin: + t = JOIN_TYPE_LEFT + case ast.RightJoin: + t = JOIN_TYPE_RIGHT + } + + if j.NaturalJoin { + joinCon = NewNaturalJoinCond() + } else if j.StraightJoin { + //TODO: + } + + if j.ExplicitParens { + //TODO: + } + + l := transformResultSetNodeToTableExpr(j.Left) + + if j.Right == nil { + return NewJoinTableExpr(t, l, nil, joinCon) + } + r := transformResultSetNodeToTableExpr(j.Right) + + if j.On != nil { + onE := transformExprNodeToExpr(j.On.Expr) + joinCon = NewOnJoinCond(onE) + } else if j.Using != nil { + iList := transformColumnNameListToNameList(j.Using) + joinCon = NewUsingJoinCond(iList) + } + + return NewJoinTableExpr(t, l, r, joinCon) +} + +//transform ast.Join to tree.ParenTableExpr +func transformJoinToParenTableExpr(j *ast.Join) *ParenTableExpr { + if j.ExplicitParens { + j.ExplicitParens = false + jt := transformJoinToJoinTableExpr(j) + return NewParenTableExpr(jt) + } + panic(fmt.Errorf("Need ExplicitParens :%v ", j)) + return nil +} + +//transform ast.TableRefsClause to tree.From +func transformTableRefsClauseToFrom(trc *ast.TableRefsClause) *From { + var te []TableExpr = make([]TableExpr, 1) + t := transformJoinToJoinTableExpr(trc.TableRefs) + te[0] = t + return NewFrom(te) +} + +//transform ast.ColumnNameExpr to tree.UnresolvedName +func transformColumnNameExprToUnresolvedName(cne *ast.ColumnNameExpr) *UnresolvedName { + cn := cne.Name + ud, _ := NewUnresolvedName(cn.Schema.O, cn.Table.O, cn.Name.O) + return ud +} + +//transform ast.FuncCallExpr to tree.FuncExpr +func transformFuncCallExprToFuncExpr(fce *ast.FuncCallExpr) *FuncExpr { + fname, _ := NewUnresolvedName(fce.Schema.O, fce.FnName.O) + var es Exprs = make([]Expr, len(fce.Args)) + for i, arg := range fce.Args { + e := transformExprNodeToExpr(arg) + es[i] = e + } + + return NewFuncExpr(0, fname, es, nil) +} + +//transform ast.AggregateFuncExpr to tree.FuncExpr +func transformAggregateFuncExprToFuncExpr(afe *ast.AggregateFuncExpr) *FuncExpr { + fname, _ := NewUnresolvedName(afe.F) + var es Exprs = make([]Expr, len(afe.Args)) + for i, arg := range afe.Args { + e := transformExprNodeToExpr(arg) + es[i] = e + } + + var ft funcType = 0 + if afe.Distinct { + ft = FUNC_TYPE_DISTINCT + } + + var ob OrderBy + if afe.Order != nil { + ob = transformOrderByClauseToOrderBy(afe.Order) + } + return NewFuncExpr(ft, fname, es, ob) +} + +//transform ast.FuncCastExpr to tree.CastExpr +func transformFuncCastExprToCastExpr(fce *ast.FuncCastExpr) *CastExpr { + e := transformExprNodeToExpr(fce.Expr) + var t ResolvableTypeReference + switch fce.Tp.Tp { + case mysql.TypeUnspecified: + panic(fmt.Errorf("unsupported type")) + case mysql.TypeTiny: + t = TYPE_TINY + case mysql.TypeShort: + t = TYPE_SHORT + case mysql.TypeLong: + t = TYPE_LONG + case mysql.TypeFloat: + t = TYPE_FLOAT + case mysql.TypeDouble: + t = TYPE_DOUBLE + case mysql.TypeNull: + t = TYPE_NULL + case mysql.TypeTimestamp: + t = TYPE_TIMESTAMP + case mysql.TypeLonglong: + t = TYPE_LONGLONG + case mysql.TypeInt24: + t = TYPE_INT24 + case mysql.TypeDate: + t = TYPE_DATE + case mysql.TypeDuration: + t = TYPE_DURATION + case mysql.TypeDatetime: + t = TYPE_DATETIME + case mysql.TypeYear: + t = TYPE_YEAR + case mysql.TypeNewDate: + t = TYPE_NEWDATE + case mysql.TypeVarchar: + t = TYPE_VARCHAR + case mysql.TypeBit: + t = TYPE_BIT + case mysql.TypeJSON: + t = TYPE_JSON + case mysql.TypeNewDecimal: + t = TYPE_NEWDATE + case mysql.TypeEnum: + t = TYPE_ENUM + case mysql.TypeSet: + t = TYPE_SET + case mysql.TypeTinyBlob: + t = TYPE_TINY_BLOB + case mysql.TypeMediumBlob: + t = TYPE_MEDIUM_BLOB + case mysql.TypeLongBlob: + t = TYPE_LONG_BLOB + case mysql.TypeBlob: + t = TYPE_BLOB + case mysql.TypeVarString: + t = TYPE_VARSTRING + case mysql.TypeString: + t = TYPE_STRING + case mysql.TypeGeometry: + t = TYPE_GEOMETRY + default: + panic("unsupported cast type") + } + return NewCastExpr(e, t) +} + +//transform ast.RowExpr to tree.Tuple +func transformRowExprToTuple(re *ast.RowExpr) *Tuple { + var ar []Expr = make([]Expr, len(re.Values)) + for i, re := range re.Values { + ar[i] = transformExprNodeToExpr(re) + } + return NewTuple(ar) +} + +//transform ast.BetweenExpr to tree.RangeCond +func transformBetweenExprToRangeCond(be *ast.BetweenExpr) *RangeCond { + e := transformExprNodeToExpr(be.Expr) + l := transformExprNodeToExpr(be.Left) + r := transformExprNodeToExpr(be.Right) + return NewRangeCond(be.Not, e, l, r) +} + +//transform ast.ExprNode to tree.Expr +func transformExprNodeToExpr(node ast.ExprNode) Expr { + switch n := node.(type) { + case ast.ValueExpr: + if ve, ok := n.(*test_driver.ValueExpr); !ok { + panic("convert to test_driver.ValueExpr failed.") + } else { + return transformDatumToNumVal(&ve.Datum) + } + case *ast.BinaryOperationExpr: + switch n.Op { + case opcode.Plus, + opcode.Minus, + opcode.Mul, + opcode.Div, + opcode.Mod, + opcode.IntDiv, + opcode.Or, + opcode.And, + opcode.Xor, + opcode.LeftShift, + opcode.RightShift: + return transformBinaryOperationExprToBinaryExpr(n) + case opcode.EQ, + opcode.LT, + opcode.LE, + opcode.GT, + opcode.GE, + opcode.NE: + return transformBinaryOperationExprToComparisonExpr(n) + case opcode.LogicAnd: + return transformBinaryOperationExprToAndExpr(n) + case opcode.LogicOr: + return transformBinaryOperationExprToOrExpr(n) + case opcode.LogicXor: + return transformBinaryOperationExprToXorExpr(n) + } + + case *ast.UnaryOperationExpr: + switch n.Op { + case opcode.Not: + return transformUnaryOperatorExprToNotExpr(n) + } + return transformUnaryOperatorExprToUnaryExpr(n) + case *ast.IsNullExpr: + if n.Not { + return transformIsNullExprToIsNotNullExpr(n) + } else { + return transformIsNullExprToIsNullExpr(n) + } + case *ast.PatternInExpr: + return transformPatternInExprToComparisonExprIn(n) + case *ast.PatternLikeExpr: + return transformPatternLikeExprToComparisonExprIn(n) + case *ast.PatternRegexpExpr: + return transformPatternRegexpExprToComparisonExprIn(n) + case *ast.SubqueryExpr: + return transformSubqueryExprToSubquery(n) + case *ast.ExistsSubqueryExpr: + return transformExistsSubqueryExprToSubquery(n) + case *ast.CompareSubqueryExpr: + return transformCompareSubqueryExprToSubquery(n) + case *ast.ParenthesesExpr: + return transformParenthesesExprToParenExpr(n) + case *ast.ColumnNameExpr: + return transformColumnNameExprToUnresolvedName(n) + case *ast.FuncCallExpr: + return transformFuncCallExprToFuncExpr(n) + case *ast.AggregateFuncExpr: + return transformAggregateFuncExprToFuncExpr(n) + case *ast.FuncCastExpr: + return transformFuncCastExprToCastExpr(n) + case *ast.RowExpr: + return transformRowExprToTuple(n) + case *ast.BetweenExpr: + return transformBetweenExprToRangeCond(n) + } + panic(fmt.Errorf("unsupported node %v ", node)) + return nil +} + +//transform ast.WildCardField to +func transformWildCardFieldToVarName(wcf *ast.WildCardField) VarName { + sch := len(wcf.Schema.O) != 0 + tbl := len(wcf.Table.O) != 0 + if sch && tbl { + //UnresolvedName + u, _ := NewUnresolvedNameWithStar(wcf.Schema.O, wcf.Table.O) + return u + } else if tbl { + //UnresolvedName + u, _ := NewUnresolvedNameWithStar(wcf.Table.O) + return u + } else { + //* + return StarExpr() + } +} + +//transform ast.FieldList to tree.SelectExprs +func transformFieldListToSelectExprs(fl *ast.FieldList) SelectExprs { + var sea []SelectExpr = make([]SelectExpr, len(fl.Fields)) + for i, se := range fl.Fields { + var e Expr + if se.Expr != nil { + e = transformExprNodeToExpr(se.Expr) + } else { + e = transformWildCardFieldToVarName(se.WildCard) + } + + sea[i].Expr = e + sea[i].As = UnrestrictedIdentifier(se.AsName.O) + } + return sea +} + +//transform ast.GroupByClause to tree.GroupBy +func transformGroupByClauseToGroupBy(gbc *ast.GroupByClause) GroupBy { + var gb []Expr = make([]Expr, len(gbc.Items)) + for i, bi := range gbc.Items { + gb[i] = transformExprNodeToExpr(bi.Expr) + } + return gb +} + +//transform ast.ByItem to tree.Order +func transformByItemToOrder(bi *ast.ByItem) *Order { + e := transformExprNodeToExpr(bi.Expr) + var a Direction + if bi.Desc { + a = Descending + } else { + a = Ascending + } + return NewOrder(e, a, bi.NullOrder) +} + +//transform ast.OrderByClause to tree.OrderBy +func transformOrderByClauseToOrderBy(obc *ast.OrderByClause) OrderBy { + var ob []*Order = make([]*Order, len(obc.Items)) + for i, obi := range obc.Items { + ob[i] = transformByItemToOrder(obi) + } + return ob +} + +//transform ast.HavingClause to tree.Where +func transformHavingClauseToWhere(hc *ast.HavingClause) *Where { + e := transformExprNodeToExpr(hc.Expr) + return NewWhere(e) +} + +//transform ast.Limit to tree.Limit +func transformLimitToLimit(l *ast.Limit) *Limit { + o := transformExprNodeToExpr(l.Offset) + c := transformExprNodeToExpr(l.Count) + return NewLimit(o, c) +} + +//transform ast.SelectStmt to tree.SelectClause +func transformSelectStmtToSelectClause(ss *ast.SelectStmt) *SelectClause { + var from *From = nil + if ss.From != nil { + from = transformTableRefsClauseToFrom(ss.From) + } + + var where *Where = nil + if ss.Where != nil { + where = NewWhere(transformExprNodeToExpr(ss.Where)) + } + + sea := transformFieldListToSelectExprs(ss.Fields) + + var gb []Expr = nil + if ss.GroupBy != nil { + gb = transformGroupByClauseToGroupBy(ss.GroupBy) + } + + var having *Where = nil + if ss.Having != nil { + having = transformHavingClauseToWhere(ss.Having) + } + + return &SelectClause{ + From: from, + Distinct: ss.Distinct, + Where: where, + Exprs: sea, + GroupBy: gb, + Having: having, + } +} + +//transform ast.SelectStmt to tree.Select +func transformSelectStmtToSelect(ss *ast.SelectStmt) *Select { + sc := transformSelectStmtToSelectClause(ss) + + var ob []*Order = nil + if ss.OrderBy != nil { + ob = transformOrderByClauseToOrderBy(ss.OrderBy) + } + + var lmt *Limit + if ss.Limit != nil { + lmt = transformLimitToLimit(ss.Limit) + } + + return &Select{ + Select: sc, + OrderBy: ob, + Limit: lmt, + } +} + +//transform ast.SelectStmt(IsInBraces is true) to tree.ParenSelect +func transformSelectStmtToParenSelect(ss *ast.SelectStmt) *ParenSelect { + if !ss.IsInBraces { + panic(fmt.Errorf("only in brace")) + } + ss.IsInBraces = false + s := transformSelectStmtToSelect(ss) + return &ParenSelect{ + Select: s, + } +} + +//transform ast.SelectStmt to tree.SelectStatement +func transformSelectStmtToSelectStatement(ss *ast.SelectStmt) SelectStatement { + if ss.IsInBraces { + return transformSelectStmtToParenSelect(ss) + } else { + return transformSelectStmtToSelectClause(ss) + } +} diff --git a/pkg/sql/tree/transformer_test.go b/pkg/sql/tree/transformer_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f81a130c044c8dcc63874f7464d42a0ce3559e91 --- /dev/null +++ b/pkg/sql/tree/transformer_test.go @@ -0,0 +1,3539 @@ +package tree + +import ( + "github.com/pingcap/parser" + "github.com/pingcap/parser/ast" + "github.com/pingcap/parser/model" + "github.com/pingcap/parser/opcode" + "github.com/pingcap/parser/test_driver" + _ "github.com/pingcap/parser/test_driver" + "github.com/pingcap/parser/types" + "go/constant" + "math" + "reflect" + "testing" +) + +/** +https://github.com/pingcap/parser/blob/master/docs/quickstart.md +*/ +func TestParser(t *testing.T) { + p := parser.New() + + sql := `SELECT u.a,(SELECT t.a FROM sa.t,u) + from u,(SELECT t.a,u.a FROM sa.t,u where t.a = u.a) + where (u.a,u.b,u.c) in (SELECT t.a,u.a,t.b * u.b tubb + FROM sa.t join u on t.c = u.c or t.d != u.d + join v on u.a != v.a + where t.a = u.a and t.b > u.b + group by t.a,u.a,(t.b+u.b+v.b) + having t.a = 'jj' and v.c > 1000 + order by t.a asc,u.a desc,v.d asc,tubb + limit 100,2000) + +;` + + stmtNodes, _, err := p.Parse(sql, "", "") + if err != nil { + t.Errorf("parser parse failed.error:%v", err) + return + } + + for _, _ = range stmtNodes { + + } +} + +func Test_transformDatumToNumVal(t *testing.T) { + type args struct { + datum *test_driver.Datum + } + + t1 := test_driver.NewDatum(math.MaxInt64) + t2 := test_driver.NewDatum(math.MinInt64) + t3 := test_driver.NewDatum(nil) + //this case is unwanted. Datum.SetUint64 is wrong. + t4 := test_driver.NewDatum(math.MaxUint64 / 2) + t5 := test_driver.NewDatum(0) + t6 := test_driver.NewDatum(math.MaxFloat32) + t7 := test_driver.NewDatum(-math.MaxFloat32) + t8 := test_driver.NewDatum(math.MaxFloat64) + t9 := test_driver.NewDatum(-math.MaxFloat64) + + s := "a string" + t10 := test_driver.NewDatum(s) + t11 := test_driver.NewDatum(true) + t12 := test_driver.NewDatum(false) + + tests := []struct { + name string + args args + want *NumVal + }{ + {"t1", args{&t1}, NewNumVal(constant.MakeInt64(math.MaxInt64), "", false)}, + {"t2", args{&t2}, NewNumVal(constant.MakeInt64(math.MinInt64), "", false)}, + {"t3", args{&t3}, NewNumVal(constant.MakeUnknown(), "", false)}, + {"t4", args{&t4}, NewNumVal(constant.MakeUint64(math.MaxUint64/2), "", false)}, + {"t5", args{&t5}, NewNumVal(constant.MakeUint64(0), "", false)}, + {"t6", args{&t6}, NewNumVal(constant.MakeFloat64(math.MaxFloat32), "", false)}, + {"t7", args{&t7}, NewNumVal(constant.MakeFloat64(-math.MaxFloat32), "", false)}, + {"t8", args{&t8}, NewNumVal(constant.MakeFloat64(math.MaxFloat64), "", false)}, + {"t9", args{&t9}, NewNumVal(constant.MakeFloat64(-math.MaxFloat64), "", false)}, + {"t10", args{&t10}, NewNumVal(constant.MakeString(s), "", false)}, + {"t11", args{&t11}, NewNumVal(constant.MakeInt64(1), "", false)}, + {"t12", args{&t12}, NewNumVal(constant.MakeInt64(0), "", false)}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := transformDatumToNumVal(tt.args.datum); !reflect.DeepEqual(got, tt.want) { + t.Errorf("transformDatumToNumVal() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_transformExprNodeToExpr(t *testing.T) { + type args struct { + node ast.ExprNode + } + + t1 := ast.NewValueExpr(math.MaxInt64, "", "") + t2 := ast.NewValueExpr(math.MinInt64, "", "") + t3 := ast.NewValueExpr(nil, "", "") + //this case is unwanted. Datum.SetUint64 is wrong. + t4 := ast.NewValueExpr(math.MaxUint64/2, "", "") + t5 := ast.NewValueExpr(0, "", "") + t6 := ast.NewValueExpr(math.MaxFloat32, "", "") + t7 := ast.NewValueExpr(-math.MaxFloat32, "", "") + t8 := ast.NewValueExpr(math.MaxFloat64, "", "") + t9 := ast.NewValueExpr(-math.MaxFloat64, "", "") + s := "a string" + t10 := ast.NewValueExpr(s, "", "") + + e1 := ast.NewValueExpr(1, "", "") + e2 := ast.NewValueExpr(2, "", "") + e3 := ast.NewValueExpr(3, "", "") + e4 := ast.NewValueExpr(4, "", "") + e5 := ast.NewValueExpr(5, "", "") + e6 := ast.NewValueExpr(6, "", "") + eTrue := ast.NewValueExpr(true, "", "") + eFalse := ast.NewValueExpr(false, "", "") + + f1 := NewNumVal(constant.MakeInt64(1), "", false) + f2 := NewNumVal(constant.MakeInt64(2), "", false) + f3 := NewNumVal(constant.MakeInt64(3), "", false) + f4 := NewNumVal(constant.MakeInt64(4), "", false) + f5 := NewNumVal(constant.MakeInt64(5), "", false) + f6 := NewNumVal(constant.MakeInt64(6), "", false) + fTrue := NewNumVal(constant.MakeInt64(1), "", false) + fFalse := NewNumVal(constant.MakeInt64(0), "", false) + + //2 * 3 + t11 := &ast.BinaryOperationExpr{ + Op: opcode.Mul, + L: e2, + R: e3, + } + + t11Want := NewBinaryExpr(MULTI, + f2, + f3) + + //1 + 2 * 3 + t12 := &ast.BinaryOperationExpr{ + Op: opcode.Plus, + L: e1, + R: t11, + } + + t12Want := NewBinaryExpr(PLUS, + f1, + t11Want) + + //1 + 2 * 3 + 4 + t13 := &ast.BinaryOperationExpr{ + Op: opcode.Plus, + L: t12, + R: e4, + } + + t13Want := NewBinaryExpr(PLUS, + t12Want, + f4, + ) + + //1 + 2 * 3 + 4 - 5 + t14 := &ast.BinaryOperationExpr{ + Op: opcode.Minus, + L: t13, + R: e5, + } + + t14Want := NewBinaryExpr(MINUS, + t13Want, + f5, + ) + + //-1 * 2 + t15_1 := &ast.UnaryOperationExpr{ + Op: opcode.Minus, + V: e1, + } + + t15 := &ast.BinaryOperationExpr{ + Op: opcode.Mul, + L: t15_1, + R: e2, + } + + t15Want := NewBinaryExpr(MULTI, + NewUnaryExpr(UNARY_MINUS, f1), + f2, + ) + + //+1 * 2 + t16_1 := &ast.UnaryOperationExpr{ + Op: opcode.Plus, + V: e1, + } + + t16 := &ast.BinaryOperationExpr{ + Op: opcode.Mul, + L: t16_1, + R: e2, + } + + t16Want := NewBinaryExpr(MULTI, + NewUnaryExpr(UNARY_PLUS, f1), + f2, + ) + + //~1 * 2 + t17_1 := &ast.UnaryOperationExpr{ + Op: opcode.BitNeg, + V: e1, + } + + t17 := &ast.BinaryOperationExpr{ + Op: opcode.Mul, + L: t17_1, + R: e2, + } + + t17Want := NewBinaryExpr(MULTI, + NewUnaryExpr(UNARY_TILDE, f1), + f2, + ) + + //!1 + t18 := &ast.UnaryOperationExpr{ + Op: opcode.Not2, + V: e1, + } + + t18Want := NewUnaryExpr(UNARY_MARK, f1) + + //1 | 2 + t21 := &ast.BinaryOperationExpr{ + Op: opcode.Or, + L: e1, + R: e2, + } + + t21Want := NewBinaryExpr(BIT_OR, + f1, + f2) + + //1 & 2 + t22 := &ast.BinaryOperationExpr{ + Op: opcode.And, + L: e1, + R: e2, + } + + t22Want := NewBinaryExpr(BIT_AND, + f1, + f2) + + //1 ^ 2 + t23 := &ast.BinaryOperationExpr{ + Op: opcode.Xor, + L: e1, + R: e2, + } + + t23Want := NewBinaryExpr(BIT_XOR, + f1, + f2) + + //1 << 2 + t24 := &ast.BinaryOperationExpr{ + Op: opcode.LeftShift, + L: e1, + R: e2, + } + + t24Want := NewBinaryExpr(LEFT_SHIFT, + f1, + f2) + + //1 >> 2 + t25 := &ast.BinaryOperationExpr{ + Op: opcode.RightShift, + L: e1, + R: e2, + } + + t25Want := NewBinaryExpr(RIGHT_SHIFT, + f1, + f2) + + //1 + 2 * 3 + 4 - 5 / 6 + t26_1 := &ast.BinaryOperationExpr{ + Op: opcode.Div, + L: e5, + R: e6, + } + + t26 := &ast.BinaryOperationExpr{ + Op: opcode.Minus, + L: t13, + R: t26_1, + } + + t26want_1 := NewBinaryExpr(DIV, f5, f6) + t26Want := NewBinaryExpr(MINUS, + t13Want, + t26want_1, + ) + + //1 % 2 + t27 := &ast.BinaryOperationExpr{ + Op: opcode.Mod, + L: e1, + R: e2, + } + + t27Want := NewBinaryExpr(MOD, + f1, + f2) + + //1 div 2 + t28 := &ast.BinaryOperationExpr{ + Op: opcode.IntDiv, + L: e1, + R: e2, + } + + t28Want := NewBinaryExpr(INTEGER_DIV, + f1, + f2) + + //1 = 2 + t29 := &ast.BinaryOperationExpr{ + Op: opcode.EQ, + L: e1, + R: e2, + } + + t29Want := NewComparisonExpr(EQUAL, + f1, + f2) + + //1 < 2 + t30 := &ast.BinaryOperationExpr{ + Op: opcode.LT, + L: e1, + R: e2, + } + + t30Want := NewComparisonExpr(LESS_THAN, + f1, + f2) + + //1 <= 2 + t31 := &ast.BinaryOperationExpr{ + Op: opcode.LE, + L: e1, + R: e2, + } + + t31Want := NewComparisonExpr(LESS_THAN_EQUAL, + f1, + f2) + + //1 > 2 + t32 := &ast.BinaryOperationExpr{ + Op: opcode.GT, + L: e1, + R: e2, + } + + t32Want := NewComparisonExpr(GREAT_THAN, + f1, + f2) + + //1 >= 2 + t33 := &ast.BinaryOperationExpr{ + Op: opcode.GE, + L: e1, + R: e2, + } + + t33Want := NewComparisonExpr(GREAT_THAN_EQUAL, + f1, + f2) + + //1 <>,!= 2 + t34 := &ast.BinaryOperationExpr{ + Op: opcode.NE, + L: e1, + R: e2, + } + + t34Want := NewComparisonExpr(NOT_EQUAL, + f1, + f2) + + //1 and 0 + t35 := &ast.BinaryOperationExpr{ + Op: opcode.LogicAnd, + L: e1, + R: e2, + } + + t35Want := NewAndExpr(f1, f2) + + //1 or 0 + t36 := &ast.BinaryOperationExpr{ + Op: opcode.LogicOr, + L: e1, + R: e2, + } + + t36Want := NewOrExpr(f1, f2) + + //not 1 + t37 := &ast.UnaryOperationExpr{ + Op: opcode.Not, + V: e1, + } + + t37Want := NewNotExpr(f1) + + //1 xor 0 + t38 := &ast.BinaryOperationExpr{ + Op: opcode.LogicXor, + L: e1, + R: e2, + } + + t38Want := NewXorExpr(f1, f2) + + // is null + t39 := &ast.IsNullExpr{ + Expr: e1, + Not: false, + } + + t39Want := NewIsNullExpr(f1) + + // is not null + t40 := &ast.IsNullExpr{ + Expr: e1, + Not: true, + } + + t40Want := NewIsNotNullExpr(f1) + + //2 IN (1,2,3,4); + t41 := &ast.PatternInExpr{ + Expr: e2, + List: []ast.ExprNode{e1, e2, e3, e4}, + Not: false, + Sel: nil, + } + + t41Want := NewComparisonExpr(IN, f2, &ExprList{ + Exprs: []Expr{f1, f2, f3, f4}, + }) + + //2 NOT IN (1,2,3,4); + t42 := &ast.PatternInExpr{ + Expr: e2, + List: []ast.ExprNode{e1, e2, e3, e4}, + Not: true, + Sel: nil, + } + + t42Want := NewComparisonExpr(NOT_IN, f2, &ExprList{ + Exprs: []Expr{f1, f2, f3, f4}, + }) + + //2 LIKE 'xxx'; + t43 := &ast.PatternLikeExpr{ + Expr: e1, + Pattern: e2, + Not: false, + Escape: 0, + PatChars: nil, + PatTypes: nil, + } + + t43Want := NewComparisonExpr(LIKE, f1, f2) + + //2 NOT LIKE 'xxx'; + t44 := &ast.PatternLikeExpr{ + Expr: e1, + Pattern: e2, + Not: true, + Escape: 0, + PatChars: nil, + PatTypes: nil, + } + + t44Want := NewComparisonExpr(NOT_LIKE, f1, f2) + + //2 REGEXP 'xxx'; + t45 := &ast.PatternRegexpExpr{ + Expr: e1, + Pattern: e2, + Not: false, + Re: nil, + Sexpr: nil, + } + + t45Want := NewComparisonExpr(REG_MATCH, f1, f2) + + //2 NOT REGEXP 'xxx'; + t46 := &ast.PatternRegexpExpr{ + Expr: e1, + Pattern: e2, + Not: true, + Re: nil, + Sexpr: nil, + } + + t46Want := NewComparisonExpr(NOT_REG_MATCH, f1, f2) + + t47subq, t47want_subq := gen_transform_t1() + + //SubqueryExpr SELECT t.a FROM sa.t,u + t47 := &ast.SubqueryExpr{ + Query: t47subq, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + t47Want := NewSubquery(t47want_subq.Select, false) + + //ExistsSubqueryExpr + t48 := &ast.ExistsSubqueryExpr{ + Sel: e1, + Not: true, + } + + //just for passing the case + var _ SelectStatement = f1 + t48Want := NewSubquery(f1, true) + + //CompareSubqueryExpr + t49 := &ast.CompareSubqueryExpr{ + L: e1, + Op: opcode.GT, + R: e2, + All: true, + } + + //just for passing the case + var _ SelectStatement = f2 + t49Want := NewComparisonExprWithSubop(GREAT_THAN, ALL, f1, f2) + + // '(' e1 ')' + t50 := &ast.ParenthesesExpr{Expr: e1} + + t50Want := NewParenExpr(f1) + + tests := []struct { + name string + args args + want Expr + }{ + {"t1", args{t1}, NewNumVal(constant.MakeInt64(math.MaxInt64), "", false)}, + {"t2", args{t2}, NewNumVal(constant.MakeInt64(math.MinInt64), "", false)}, + {"t3", args{t3}, NewNumVal(constant.MakeUnknown(), "", false)}, + {"t4", args{t4}, NewNumVal(constant.MakeUint64(math.MaxUint64/2), "", false)}, + {"t5", args{t5}, NewNumVal(constant.MakeUint64(0), "", false)}, + {"t6", args{t6}, NewNumVal(constant.MakeFloat64(math.MaxFloat32), "", false)}, + {"t7", args{t7}, NewNumVal(constant.MakeFloat64(-math.MaxFloat32), "", false)}, + {"t8", args{t8}, NewNumVal(constant.MakeFloat64(math.MaxFloat64), "", false)}, + {"t9", args{t9}, NewNumVal(constant.MakeFloat64(-math.MaxFloat64), "", false)}, + {"t10", args{t10}, NewNumVal(constant.MakeString(s), "", false)}, + {"t11", args{t11}, t11Want}, + {"t12", args{t12}, t12Want}, + {"t13", args{t13}, t13Want}, + {"t14", args{t14}, t14Want}, + {"t15", args{t15}, t15Want}, + {"t16", args{t16}, t16Want}, + {"t17", args{t17}, t17Want}, + {"t18", args{t18}, t18Want}, + {"t19", args{eTrue}, fTrue}, + {"t20", args{eFalse}, fFalse}, + {"t21", args{t21}, t21Want}, + {"t22", args{t22}, t22Want}, + {"t23", args{t23}, t23Want}, + {"t24", args{t24}, t24Want}, + {"t25", args{t25}, t25Want}, + {"t26", args{t26}, t26Want}, + {"t27", args{t27}, t27Want}, + {"t28", args{t28}, t28Want}, + {"t29", args{t29}, t29Want}, + {"t30", args{t30}, t30Want}, + {"t31", args{t31}, t31Want}, + {"t32", args{t32}, t32Want}, + {"t33", args{t33}, t33Want}, + {"t34", args{t34}, t34Want}, + {"t35", args{t35}, t35Want}, + {"t36", args{t36}, t36Want}, + {"t37", args{t37}, t37Want}, + {"t38", args{t38}, t38Want}, + {"t39", args{t39}, t39Want}, + {"t40", args{t40}, t40Want}, + {"t41", args{t41}, t41Want}, + {"t42", args{t42}, t42Want}, + {"t43", args{t43}, t43Want}, + {"t44", args{t44}, t44Want}, + {"t45", args{t45}, t45Want}, + {"t46", args{t46}, t46Want}, + {"t47", args{t47}, t47Want}, + {"t48", args{t48}, t48Want}, + {"t49", args{t49}, t49Want}, + {"t50", args{t50}, t50Want}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := transformExprNodeToExpr(tt.args.node); !reflect.DeepEqual(got, tt.want) { + t.Errorf("transformExprNodeToExpr() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_transformColumnNameListToNameList(t *testing.T) { + type args struct { + cn []*ast.ColumnName + } + l1 := []*ast.ColumnName{ + &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{}, + Name: model.CIStr{"A", "a"}, + }, + &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{}, + Name: model.CIStr{"B", "b"}, + }, + &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{}, + Name: model.CIStr{"C", "c"}, + }, + } + + l1Want := IdentifierList{ + "A", + "B", + "C", + } + tests := []struct { + name string + args args + want IdentifierList + }{ + {"t1", args{l1}, l1Want}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := transformColumnNameListToNameList(tt.args.cn); !reflect.DeepEqual(got, tt.want) { + t.Errorf("transformColumnNameListToNameList() = %v, want %v", got, tt.want) + } + }) + } +} + +func gen_transform_t1() (*ast.SelectStmt, *Select) { + //SELECT t.a FROM sa.t ; + //SELECT t.a FROM sa.t,u ; + t1TableName := &ast.TableName{ + Schema: model.CIStr{"sa", "sa"}, + Name: model.CIStr{"t", "t"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource := &ast.TableSource{ + Source: t1TableName, + AsName: model.CIStr{}, + } + + t1TableName2 := &ast.TableName{ + Schema: model.CIStr{}, + Name: model.CIStr{"u", "u"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource2 := &ast.TableSource{ + Source: t1TableName2, + AsName: model.CIStr{}, + } + + t1Join := &ast.Join{ + Left: t1TableSource, + Right: t1TableSource2, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join} + + t1ColumnName := &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{"t", "t"}, + Name: model.CIStr{"a", "a"}, + } + t1ColumnNameExpr := &ast.ColumnNameExpr{ + Name: t1ColumnName, + Refer: nil, + } + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1ColumnNameExpr, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + t1wantTableName := &TableName{ + objName: objName{ + ObjectName: "t", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "sa", + ExplicitCatalog: false, + ExplicitSchema: true, + }, + }, + } + + t1wantAliasedTableExpr := &AliasedTableExpr{ + Expr: t1wantTableName, + As: AliasClause{}, + } + + t1wantTableName2 := &TableName{ + objName: objName{ + ObjectName: "u", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "", + ExplicitCatalog: false, + ExplicitSchema: false, + }, + }, + } + + t1wantAliasedTableExpr2 := &AliasedTableExpr{ + Expr: t1wantTableName2, + As: AliasClause{}, + } + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: t1wantAliasedTableExpr, + Right: t1wantAliasedTableExpr2, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + t1wantFied, _ := NewUnresolvedName("", "t", "a") + + t1wantFieldList := []SelectExpr{ + { + Expr: t1wantFied, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t2() (*ast.SelectStmt, *Select) { + //SELECT t.a FROM sa.t,u,v + t1TableName := &ast.TableName{ + Schema: model.CIStr{"sa", "sa"}, + Name: model.CIStr{"t", "t"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource := &ast.TableSource{ + Source: t1TableName, + AsName: model.CIStr{}, + } + + t1TableName2 := &ast.TableName{ + Schema: model.CIStr{}, + Name: model.CIStr{"u", "u"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource2 := &ast.TableSource{ + Source: t1TableName2, + AsName: model.CIStr{}, + } + + t1TableName3 := &ast.TableName{ + Schema: model.CIStr{}, + Name: model.CIStr{"v", "v"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource3 := &ast.TableSource{ + Source: t1TableName3, + AsName: model.CIStr{}, + } + + t1Join := &ast.Join{ + Left: t1TableSource, + Right: t1TableSource2, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1Join2 := &ast.Join{ + Left: t1Join, + Right: t1TableSource3, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join2} + + t1ColumnName := &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{"t", "t"}, + Name: model.CIStr{"a", "a"}, + } + t1ColumnNameExpr := &ast.ColumnNameExpr{ + Name: t1ColumnName, + Refer: nil, + } + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1ColumnNameExpr, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + t1wantTableName := &TableName{ + objName: objName{ + ObjectName: "t", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "sa", + ExplicitCatalog: false, + ExplicitSchema: true, + }, + }, + } + + t1wantAliasedTableExpr := &AliasedTableExpr{ + Expr: t1wantTableName, + As: AliasClause{}, + } + + t1wantTableName2 := &TableName{ + objName: objName{ + ObjectName: "u", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "", + ExplicitCatalog: false, + ExplicitSchema: false, + }, + }, + } + + t1wantAliasedTableExpr2 := &AliasedTableExpr{ + Expr: t1wantTableName2, + As: AliasClause{}, + } + + t1wantTableName3 := &TableName{ + objName: objName{ + ObjectName: "v", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "", + ExplicitCatalog: false, + ExplicitSchema: false, + }, + }, + } + + t1wantAliasedTableExpr3 := &AliasedTableExpr{ + Expr: t1wantTableName3, + As: AliasClause{}, + } + + t1wantJoin_1_2 := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: t1wantAliasedTableExpr, + Right: t1wantAliasedTableExpr2, + Cond: nil, + } + + t1wantJoin_1_2_Join_3 := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: t1wantJoin_1_2, + Right: t1wantAliasedTableExpr3, + Cond: nil, + } + + t1wantTableExprArray := []TableExpr{ + t1wantJoin_1_2_Join_3, + } + + t1wantFrom := &From{Tables: t1wantTableExprArray} + + t1wantFied, _ := NewUnresolvedName("", "t", "a") + + t1wantFieldList := []SelectExpr{ + { + Expr: t1wantFied, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t3() (*ast.SelectStmt, *Select) { + //SELECT t.a,u.a FROM sa.t,u where t.a = u.a + t1TableName := &ast.TableName{ + Schema: model.CIStr{"sa", "sa"}, + Name: model.CIStr{"t", "t"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource := &ast.TableSource{ + Source: t1TableName, + AsName: model.CIStr{}, + } + + t1TableName2 := &ast.TableName{ + Schema: model.CIStr{}, + Name: model.CIStr{"u", "u"}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + t1TableSource2 := &ast.TableSource{ + Source: t1TableName2, + AsName: model.CIStr{}, + } + + t1Join := &ast.Join{ + Left: t1TableSource, + Right: t1TableSource2, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join} + + t1ColumnName := &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{"t", "t"}, + Name: model.CIStr{"a", "a"}, + } + t1ColumnNameExpr := &ast.ColumnNameExpr{ + Name: t1ColumnName, + Refer: nil, + } + + t1ColumnName2 := &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{"u", "u"}, + Name: model.CIStr{"a", "a"}, + } + t1ColumnNameExpr2 := &ast.ColumnNameExpr{ + Name: t1ColumnName2, + Refer: nil, + } + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1ColumnNameExpr, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1ColumnNameExpr2, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1ColumnName3 := &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{"t", "t"}, + Name: model.CIStr{"a", "a"}, + } + t1Where1 := &ast.ColumnNameExpr{ + Name: t1ColumnName3, + Refer: nil, + } + + t1ColumnName4 := &ast.ColumnName{ + Schema: model.CIStr{}, + Table: model.CIStr{"u", "u"}, + Name: model.CIStr{"a", "a"}, + } + t1Where2 := &ast.ColumnNameExpr{ + Name: t1ColumnName4, + Refer: nil, + } + + t1Where := &ast.BinaryOperationExpr{ + Op: opcode.EQ, + L: t1Where1, + R: t1Where2, + } + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t1Where, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + t1wantTableName := &TableName{ + objName: objName{ + ObjectName: "t", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "sa", + ExplicitCatalog: false, + ExplicitSchema: true, + }, + }, + } + + t1wantAliasedTableExpr := &AliasedTableExpr{ + Expr: t1wantTableName, + As: AliasClause{}, + } + + t1wantTableName2 := &TableName{ + objName: objName{ + ObjectName: "u", + ObjectNamePrefix: ObjectNamePrefix{ + CatalogName: "", + SchemaName: "", + ExplicitCatalog: false, + ExplicitSchema: false, + }, + }, + } + + t1wantAliasedTableExpr2 := &AliasedTableExpr{ + Expr: t1wantTableName2, + As: AliasClause{}, + } + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: t1wantAliasedTableExpr, + Right: t1wantAliasedTableExpr2, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + t1wantField1, _ := NewUnresolvedName("", "t", "a") + t1wantField2, _ := NewUnresolvedName("", "u", "a") + + t1wantWhere1, _ := NewUnresolvedName("", "t", "a") + t1wantWhere2, _ := NewUnresolvedName("", "u", "a") + + t1wantWhereExpr := &ComparisonExpr{ + Op: EQUAL, + SubOp: 0, + Left: t1wantWhere1, + Right: t1wantWhere2, + } + + t1wantFieldList := []SelectExpr{ + { + Expr: t1wantField1, + As: "", + }, + { + Expr: t1wantField2, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(t1wantWhereExpr), + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_var_ref(schema, table, name string) *ast.ColumnNameExpr { + var_name := &ast.ColumnName{ + Schema: model.CIStr{schema, schema}, + Table: model.CIStr{table, table}, + Name: model.CIStr{name, name}, + } + var_ := &ast.ColumnNameExpr{ + Name: var_name, + Refer: nil, + } + return var_ +} + +func gen_binary_expr(op opcode.Op, l, r ast.ExprNode) *ast.BinaryOperationExpr { + return &ast.BinaryOperationExpr{ + Op: op, + L: l, + R: r, + } +} + +func gen_table(sch, name string) *ast.TableSource { + sa_t_name := &ast.TableName{ + Schema: model.CIStr{sch, sch}, + Name: model.CIStr{name, name}, + DBInfo: nil, + TableInfo: nil, + IndexHints: nil, + PartitionNames: nil, + TableSample: nil, + } + + sa_t := &ast.TableSource{ + Source: sa_t_name, + AsName: model.CIStr{}, + } + return sa_t +} + +func gen_want_table(sch, name string) *AliasedTableExpr { + want_sa_t_name := NewTableName(Identifier(name), ObjectNamePrefix{ + CatalogName: "", + SchemaName: Identifier(sch), + ExplicitCatalog: false, + ExplicitSchema: len(sch) != 0, + }) + + want_sa_t := &AliasedTableExpr{ + Expr: want_sa_t_name, + As: AliasClause{}, + } + return want_sa_t +} + +func gen_transform_t4() (*ast.SelectStmt, *Select) { + //SELECT t.a,u.a,t.b * u.b FROM sa.t,u where t.a = u.a and t.b > u.b + sa_t := gen_table("sa", "t") + + u := gen_table("", "u") + + sa_t_cross_u := &ast.Join{ + Left: sa_t, + Right: u, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + t1TableRef := &ast.TableRefsClause{TableRefs: sa_t_cross_u} + + t_a := gen_var_ref("", "t", "a") + t_b := gen_var_ref("", "t", "b") + + u_a := gen_var_ref("", "u", "a") + u_b := gen_var_ref("", "u", "b") + + t_b_multi_u_b := gen_binary_expr(opcode.Mul, t_b, u_b) + select_fields := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: u_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_b_multi_u_b, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: select_fields} + + //t.a = u.a + t_a_eq_u_a := gen_binary_expr(opcode.EQ, t_a, u_a) + + //t.b > u.b + t_b_gt_u_b := gen_binary_expr(opcode.GT, t_b, u_b) + + //t.a = u.a and t.b > u.b + t_a_eq_u_a_and_t_b_gt_u_b := gen_binary_expr(opcode.LogicAnd, t_a_eq_u_a, t_b_gt_u_b) + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t_a_eq_u_a_and_t_b_gt_u_b, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + want_sa_t := gen_want_table("sa", "t") + + want_u := gen_want_table("", "u") + + want_table_refs := []TableExpr{ + &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_sa_t, + Right: want_u, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: want_table_refs} + + want_t_a, _ := NewUnresolvedName("", "t", "a") + want_t_b, _ := NewUnresolvedName("", "t", "b") + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + + //t.b * u.b + want_t_b_multi_u_b := NewBinaryExpr(MULTI, want_t_b, want_u_b) + + //t.a = u.a + want_t_a_eq_u_a := NewComparisonExpr(EQUAL, want_t_a, want_u_a) + + //t.b > u.b + want_t_b_gt_u_b := NewComparisonExpr(GREAT_THAN, want_t_b, want_u_b) + + //t.a = u.a and t.b > u.b + want_t_a_eq_u_a_logicand_t_b_gt_u_b := NewAndExpr(want_t_a_eq_u_a, want_t_b_gt_u_b) + + t1wantFieldList := []SelectExpr{ + { + Expr: want_t_a, + As: "", + }, + { + Expr: want_u_a, + As: "", + }, + { + Expr: want_t_b_multi_u_b, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_t_a_eq_u_a_logicand_t_b_gt_u_b), + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t5() (*ast.SelectStmt, *Select) { + //SELECT t.a,u.a,t.b * u.b FROM sa.t join u on t.c = u.c or t.d != u.d where t.a = u.a and t.b > u.b + t_a := gen_var_ref("", "t", "a") + t_b := gen_var_ref("", "t", "b") + t_c := gen_var_ref("", "t", "c") + t_d := gen_var_ref("", "t", "d") + + u_a := gen_var_ref("", "u", "a") + u_b := gen_var_ref("", "u", "b") + u_c := gen_var_ref("", "u", "c") + u_d := gen_var_ref("", "u", "d") + + sa_t := gen_table("sa", "t") + + u := gen_table("", "u") + + t_c_eq_u_c := gen_binary_expr(opcode.EQ, t_c, u_c) + t_d_ne_u_d := gen_binary_expr(opcode.NE, t_d, u_d) + t_c_eq_u_c_or_t_d_ne_u_d := gen_binary_expr(opcode.LogicOr, t_c_eq_u_c, t_d_ne_u_d) + + onCond := &ast.OnCondition{Expr: t_c_eq_u_c_or_t_d_ne_u_d} + + sa_t_cross_u := &ast.Join{ + Left: sa_t, + Right: u, + Tp: ast.CrossJoin, + On: onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + t1TableRef := &ast.TableRefsClause{TableRefs: sa_t_cross_u} + + t_b_multi_u_b := gen_binary_expr(opcode.Mul, t_b, u_b) + select_fields := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: u_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_b_multi_u_b, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: select_fields} + + //t.a = u.a + t_a_eq_u_a := gen_binary_expr(opcode.EQ, t_a, u_a) + + //t.b > u.b + t_b_gt_u_b := gen_binary_expr(opcode.GT, t_b, u_b) + + //t.a = u.a and t.b > u.b + t_a_eq_u_a_and_t_b_gt_u_b := gen_binary_expr(opcode.LogicAnd, t_a_eq_u_a, t_b_gt_u_b) + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t_a_eq_u_a_and_t_b_gt_u_b, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + //========= + + want_t_a, _ := NewUnresolvedName("", "t", "a") + want_t_b, _ := NewUnresolvedName("", "t", "b") + want_t_c, _ := NewUnresolvedName("", "t", "c") + want_t_d, _ := NewUnresolvedName("", "t", "d") + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + want_u_c, _ := NewUnresolvedName("", "u", "c") + want_u_d, _ := NewUnresolvedName("", "u", "d") + + //t.c = u.c or t.d != u.d + want_t_c_eq_u_c := NewComparisonExpr(EQUAL, want_t_c, want_u_c) + want_t_d_ne_u_d := NewComparisonExpr(NOT_EQUAL, want_t_d, want_u_d) + want_t_c_eq_u_c_or_t_d_ne_u_d := NewOrExpr(want_t_c_eq_u_c, want_t_d_ne_u_d) + + want_join_on := NewOnJoinCond(want_t_c_eq_u_c_or_t_d_ne_u_d) + + want_sa_t := gen_want_table("sa", "t") + + want_u := gen_want_table("", "u") + + want_table_refs := []TableExpr{ + &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_sa_t, + Right: want_u, + Cond: want_join_on, + }, + } + t1wantFrom := &From{Tables: want_table_refs} + + //t.b * u.b + want_t_b_multi_u_b := NewBinaryExpr(MULTI, want_t_b, want_u_b) + + //t.a = u.a + want_t_a_eq_u_a := NewComparisonExpr(EQUAL, want_t_a, want_u_a) + + //t.b > u.b + want_t_b_gt_u_b := NewComparisonExpr(GREAT_THAN, want_t_b, want_u_b) + + //t.a = u.a and t.b > u.b + want_t_a_eq_u_a_logicand_t_b_gt_u_b := NewAndExpr(want_t_a_eq_u_a, want_t_b_gt_u_b) + + t1wantFieldList := []SelectExpr{ + { + Expr: want_t_a, + As: "", + }, + { + Expr: want_u_a, + As: "", + }, + { + Expr: want_t_b_multi_u_b, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_t_a_eq_u_a_logicand_t_b_gt_u_b), + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t6() (*ast.SelectStmt, *Select) { + /* + SELECT t.a,u.a,t.b * u.b + FROM sa.t join u on t.c = u.c or t.d != u.d + join v on u.a != v.a + where t.a = u.a and t.b > u.b + */ + t_a := gen_var_ref("", "t", "a") + t_b := gen_var_ref("", "t", "b") + t_c := gen_var_ref("", "t", "c") + t_d := gen_var_ref("", "t", "d") + + u_a := gen_var_ref("", "u", "a") + u_b := gen_var_ref("", "u", "b") + u_c := gen_var_ref("", "u", "c") + u_d := gen_var_ref("", "u", "d") + + v_a := gen_var_ref("", "v", "a") + //v_b := gen_var_ref("","v","b") + //v_c := gen_var_ref("","v","c") + //v_d := gen_var_ref("","v","d") + + sa_t := gen_table("sa", "t") + + u := gen_table("", "u") + + v := gen_table("", "v") + + t_c_eq_u_c := gen_binary_expr(opcode.EQ, t_c, u_c) + t_d_ne_u_d := gen_binary_expr(opcode.NE, t_d, u_d) + t_c_eq_u_c_or_t_d_ne_u_d := gen_binary_expr(opcode.LogicOr, t_c_eq_u_c, t_d_ne_u_d) + + t_u_onCond := &ast.OnCondition{Expr: t_c_eq_u_c_or_t_d_ne_u_d} + + sa_t_cross_u := &ast.Join{ + Left: sa_t, + Right: u, + Tp: ast.CrossJoin, + On: t_u_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + //u.a != v.a + u_a_ne_v_a := gen_binary_expr(opcode.NE, u_a, v_a) + + u_v_onCond := &ast.OnCondition{Expr: u_a_ne_v_a} + + sa_t_cross_u_cross_v := &ast.Join{ + Left: sa_t_cross_u, + Right: v, + Tp: ast.CrossJoin, + On: u_v_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: sa_t_cross_u_cross_v} + + t_b_multi_u_b := gen_binary_expr(opcode.Mul, t_b, u_b) + select_fields := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: u_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_b_multi_u_b, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: select_fields} + + //t.a = u.a + t_a_eq_u_a := gen_binary_expr(opcode.EQ, t_a, u_a) + + //t.b > u.b + t_b_gt_u_b := gen_binary_expr(opcode.GT, t_b, u_b) + + //t.a = u.a and t.b > u.b + t_a_eq_u_a_and_t_b_gt_u_b := gen_binary_expr(opcode.LogicAnd, t_a_eq_u_a, t_b_gt_u_b) + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t_a_eq_u_a_and_t_b_gt_u_b, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + //========= + + want_t_a, _ := NewUnresolvedName("", "t", "a") + want_t_b, _ := NewUnresolvedName("", "t", "b") + want_t_c, _ := NewUnresolvedName("", "t", "c") + want_t_d, _ := NewUnresolvedName("", "t", "d") + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + want_u_c, _ := NewUnresolvedName("", "u", "c") + want_u_d, _ := NewUnresolvedName("", "u", "d") + + want_v_a, _ := NewUnresolvedName("", "v", "a") + + //t.c = u.c or t.d != u.d + want_t_c_eq_u_c := NewComparisonExpr(EQUAL, want_t_c, want_u_c) + want_t_d_ne_u_d := NewComparisonExpr(NOT_EQUAL, want_t_d, want_u_d) + want_t_c_eq_u_c_or_t_d_ne_u_d := NewOrExpr(want_t_c_eq_u_c, want_t_d_ne_u_d) + + want_join_on := NewOnJoinCond(want_t_c_eq_u_c_or_t_d_ne_u_d) + + //u.a != v.a + want_u_a_ne_v_a := NewComparisonExpr(NOT_EQUAL, want_u_a, want_v_a) + want_u_v_join_on := NewOnJoinCond(want_u_a_ne_v_a) + + want_sa_t := gen_want_table("sa", "t") + + want_u := gen_want_table("", "u") + + want_v := gen_want_table("", "v") + + want_t_u_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_sa_t, + Right: want_u, + Cond: want_join_on, + } + + want_u_v_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_t_u_join, + Right: want_v, + Cond: want_u_v_join_on, + } + + want_table_refs := []TableExpr{ + want_u_v_join, + } + + t1wantFrom := &From{Tables: want_table_refs} + + //t.b * u.b + want_t_b_multi_u_b := NewBinaryExpr(MULTI, want_t_b, want_u_b) + + //t.a = u.a + want_t_a_eq_u_a := NewComparisonExpr(EQUAL, want_t_a, want_u_a) + + //t.b > u.b + want_t_b_gt_u_b := NewComparisonExpr(GREAT_THAN, want_t_b, want_u_b) + + //t.a = u.a and t.b > u.b + want_t_a_eq_u_a_logicand_t_b_gt_u_b := NewAndExpr(want_t_a_eq_u_a, want_t_b_gt_u_b) + + t1wantFieldList := []SelectExpr{ + { + Expr: want_t_a, + As: "", + }, + { + Expr: want_u_a, + As: "", + }, + { + Expr: want_t_b_multi_u_b, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_t_a_eq_u_a_logicand_t_b_gt_u_b), + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t7() (*ast.SelectStmt, *Select) { + /* + SELECT t.a,u.a,t.b * u.b + FROM sa.t join u on t.c = u.c or t.d != u.d + join v on u.a != v.a + where t.a = u.a and t.b > u.b + group by t.a,u.a,(t.b+u.b+v.b) + */ + t_a := gen_var_ref("", "t", "a") + t_b := gen_var_ref("", "t", "b") + t_c := gen_var_ref("", "t", "c") + t_d := gen_var_ref("", "t", "d") + + u_a := gen_var_ref("", "u", "a") + u_b := gen_var_ref("", "u", "b") + u_c := gen_var_ref("", "u", "c") + u_d := gen_var_ref("", "u", "d") + + v_a := gen_var_ref("", "v", "a") + v_b := gen_var_ref("", "v", "b") + //v_c := gen_var_ref("","v","c") + //v_d := gen_var_ref("","v","d") + + sa_t := gen_table("sa", "t") + + u := gen_table("", "u") + + v := gen_table("", "v") + + t_c_eq_u_c := gen_binary_expr(opcode.EQ, t_c, u_c) + t_d_ne_u_d := gen_binary_expr(opcode.NE, t_d, u_d) + t_c_eq_u_c_or_t_d_ne_u_d := gen_binary_expr(opcode.LogicOr, t_c_eq_u_c, t_d_ne_u_d) + + t_u_onCond := &ast.OnCondition{Expr: t_c_eq_u_c_or_t_d_ne_u_d} + + sa_t_cross_u := &ast.Join{ + Left: sa_t, + Right: u, + Tp: ast.CrossJoin, + On: t_u_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + //u.a != v.a + u_a_ne_v_a := gen_binary_expr(opcode.NE, u_a, v_a) + + u_v_onCond := &ast.OnCondition{Expr: u_a_ne_v_a} + + sa_t_cross_u_cross_v := &ast.Join{ + Left: sa_t_cross_u, + Right: v, + Tp: ast.CrossJoin, + On: u_v_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: sa_t_cross_u_cross_v} + + t_b_multi_u_b := gen_binary_expr(opcode.Mul, t_b, u_b) + select_fields := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: u_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_b_multi_u_b, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: select_fields} + + //t.a = u.a + t_a_eq_u_a := gen_binary_expr(opcode.EQ, t_a, u_a) + + //t.b > u.b + t_b_gt_u_b := gen_binary_expr(opcode.GT, t_b, u_b) + + //t.a = u.a and t.b > u.b + t_a_eq_u_a_and_t_b_gt_u_b := gen_binary_expr(opcode.LogicAnd, t_a_eq_u_a, t_b_gt_u_b) + + //group by t.a,u.a,(t.b+u.b+v.b) + + byitem_t_a := &ast.ByItem{ + Expr: t_a, + Desc: false, + NullOrder: true, + } + + byitem_u_a := &ast.ByItem{ + Expr: u_a, + Desc: false, + NullOrder: true, + } + + t_b_plus_u_b_plus_v_b := gen_binary_expr(opcode.Plus, gen_binary_expr(opcode.Plus, t_b, u_b), v_b) + + paren_t_b_plus_u_b_plus_v_b := &ast.ParenthesesExpr{Expr: t_b_plus_u_b_plus_v_b} + + byitem_t_b_plus_u_b_plus_v_b := &ast.ByItem{ + Expr: paren_t_b_plus_u_b_plus_v_b, + Desc: false, + NullOrder: true, + } + + t_groupby_item := []*ast.ByItem{ + byitem_t_a, + byitem_u_a, + byitem_t_b_plus_u_b_plus_v_b, + } + + t_groupby := &ast.GroupByClause{Items: t_groupby_item} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t_a_eq_u_a_and_t_b_gt_u_b, + Fields: t1FieldList, + GroupBy: t_groupby, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + //========= + + want_t_a, _ := NewUnresolvedName("", "t", "a") + want_t_b, _ := NewUnresolvedName("", "t", "b") + want_t_c, _ := NewUnresolvedName("", "t", "c") + want_t_d, _ := NewUnresolvedName("", "t", "d") + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + want_u_c, _ := NewUnresolvedName("", "u", "c") + want_u_d, _ := NewUnresolvedName("", "u", "d") + + want_v_a, _ := NewUnresolvedName("", "v", "a") + want_v_b, _ := NewUnresolvedName("", "v", "b") + + //t.c = u.c or t.d != u.d + want_t_c_eq_u_c := NewComparisonExpr(EQUAL, want_t_c, want_u_c) + want_t_d_ne_u_d := NewComparisonExpr(NOT_EQUAL, want_t_d, want_u_d) + want_t_c_eq_u_c_or_t_d_ne_u_d := NewOrExpr(want_t_c_eq_u_c, want_t_d_ne_u_d) + + want_join_on := NewOnJoinCond(want_t_c_eq_u_c_or_t_d_ne_u_d) + + //u.a != v.a + want_u_a_ne_v_a := NewComparisonExpr(NOT_EQUAL, want_u_a, want_v_a) + want_u_v_join_on := NewOnJoinCond(want_u_a_ne_v_a) + + want_sa_t := gen_want_table("sa", "t") + + want_u := gen_want_table("", "u") + + want_v := gen_want_table("", "v") + + want_t_u_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_sa_t, + Right: want_u, + Cond: want_join_on, + } + + want_u_v_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_t_u_join, + Right: want_v, + Cond: want_u_v_join_on, + } + + want_table_refs := []TableExpr{ + want_u_v_join, + } + + t1wantFrom := &From{Tables: want_table_refs} + + //t.b * u.b + want_t_b_multi_u_b := NewBinaryExpr(MULTI, want_t_b, want_u_b) + + //t.a = u.a + want_t_a_eq_u_a := NewComparisonExpr(EQUAL, want_t_a, want_u_a) + + //t.b > u.b + want_t_b_gt_u_b := NewComparisonExpr(GREAT_THAN, want_t_b, want_u_b) + + //t.a = u.a and t.b > u.b + want_t_a_eq_u_a_logicand_t_b_gt_u_b := NewAndExpr(want_t_a_eq_u_a, want_t_b_gt_u_b) + + want_t_b_plus_u_b_plus_v_b := NewBinaryExpr(PLUS, NewBinaryExpr(PLUS, want_t_b, want_u_b), want_v_b) + + want_paren_t_b_plus_u_b_plus_v_b := NewParenExpr(want_t_b_plus_u_b_plus_v_b) + + //group by t.a,u.a,(t.b+u.b+v.b) + want_groupby := []Expr{ + want_t_a, + want_u_a, + want_paren_t_b_plus_u_b_plus_v_b, + } + + t1wantFieldList := []SelectExpr{ + { + Expr: want_t_a, + As: "", + }, + { + Expr: want_u_a, + As: "", + }, + { + Expr: want_t_b_multi_u_b, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_t_a_eq_u_a_logicand_t_b_gt_u_b), + Exprs: t1wantFieldList, + GroupBy: want_groupby, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t8() (*ast.SelectStmt, *Select) { + /* + SELECT t.a,u.a,t.b * u.b + FROM sa.t join u on t.c = u.c or t.d != u.d + join v on u.a != v.a + where t.a = u.a and t.b > u.b + group by t.a,u.a,(t.b+u.b+v.b) + having t.a = 'jj' and v.c > 1000 + */ + t_a := gen_var_ref("", "t", "a") + t_b := gen_var_ref("", "t", "b") + t_c := gen_var_ref("", "t", "c") + t_d := gen_var_ref("", "t", "d") + + u_a := gen_var_ref("", "u", "a") + u_b := gen_var_ref("", "u", "b") + u_c := gen_var_ref("", "u", "c") + u_d := gen_var_ref("", "u", "d") + + v_a := gen_var_ref("", "v", "a") + v_b := gen_var_ref("", "v", "b") + v_c := gen_var_ref("", "v", "c") + //v_d := gen_var_ref("","v","d") + + sa_t := gen_table("sa", "t") + + u := gen_table("", "u") + + v := gen_table("", "v") + + t_c_eq_u_c := gen_binary_expr(opcode.EQ, t_c, u_c) + t_d_ne_u_d := gen_binary_expr(opcode.NE, t_d, u_d) + t_c_eq_u_c_or_t_d_ne_u_d := gen_binary_expr(opcode.LogicOr, t_c_eq_u_c, t_d_ne_u_d) + + t_u_onCond := &ast.OnCondition{Expr: t_c_eq_u_c_or_t_d_ne_u_d} + + sa_t_cross_u := &ast.Join{ + Left: sa_t, + Right: u, + Tp: ast.CrossJoin, + On: t_u_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + //u.a != v.a + u_a_ne_v_a := gen_binary_expr(opcode.NE, u_a, v_a) + + u_v_onCond := &ast.OnCondition{Expr: u_a_ne_v_a} + + sa_t_cross_u_cross_v := &ast.Join{ + Left: sa_t_cross_u, + Right: v, + Tp: ast.CrossJoin, + On: u_v_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: sa_t_cross_u_cross_v} + + t_b_multi_u_b := gen_binary_expr(opcode.Mul, t_b, u_b) + select_fields := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: u_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_b_multi_u_b, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: select_fields} + + //t.a = u.a + t_a_eq_u_a := gen_binary_expr(opcode.EQ, t_a, u_a) + + //t.b > u.b + t_b_gt_u_b := gen_binary_expr(opcode.GT, t_b, u_b) + + //t.a = u.a and t.b > u.b + t_a_eq_u_a_and_t_b_gt_u_b := gen_binary_expr(opcode.LogicAnd, t_a_eq_u_a, t_b_gt_u_b) + + //group by t.a,u.a,(t.b+u.b+v.b) + + byitem_t_a := &ast.ByItem{ + Expr: t_a, + Desc: false, + NullOrder: true, + } + + byitem_u_a := &ast.ByItem{ + Expr: u_a, + Desc: false, + NullOrder: true, + } + + t_b_plus_u_b_plus_v_b := gen_binary_expr(opcode.Plus, gen_binary_expr(opcode.Plus, t_b, u_b), v_b) + + paren_t_b_plus_u_b_plus_v_b := &ast.ParenthesesExpr{Expr: t_b_plus_u_b_plus_v_b} + + byitem_t_b_plus_u_b_plus_v_b := &ast.ByItem{ + Expr: paren_t_b_plus_u_b_plus_v_b, + Desc: false, + NullOrder: true, + } + + t_groupby_item := []*ast.ByItem{ + byitem_t_a, + byitem_u_a, + byitem_t_b_plus_u_b_plus_v_b, + } + + t_groupby := &ast.GroupByClause{Items: t_groupby_item} + + //having t.a = 'jj' and v.c > 1000 + + t_jj := ast.NewValueExpr("jj", "", "") + t_a_eq_tjj := gen_binary_expr(opcode.EQ, t_a, t_jj) + v_c_gt_1000 := gen_binary_expr(opcode.GT, v_c, ast.NewValueExpr(1000, "", "")) + t_a_eq_tjj_and_v_c_gt_1000 := gen_binary_expr(opcode.LogicAnd, t_a_eq_tjj, v_c_gt_1000) + + t_having := &ast.HavingClause{Expr: t_a_eq_tjj_and_v_c_gt_1000} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t_a_eq_u_a_and_t_b_gt_u_b, + Fields: t1FieldList, + GroupBy: t_groupby, + Having: t_having, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + //========= + + want_t_a, _ := NewUnresolvedName("", "t", "a") + want_t_b, _ := NewUnresolvedName("", "t", "b") + want_t_c, _ := NewUnresolvedName("", "t", "c") + want_t_d, _ := NewUnresolvedName("", "t", "d") + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + want_u_c, _ := NewUnresolvedName("", "u", "c") + want_u_d, _ := NewUnresolvedName("", "u", "d") + + want_v_a, _ := NewUnresolvedName("", "v", "a") + want_v_b, _ := NewUnresolvedName("", "v", "b") + want_v_c, _ := NewUnresolvedName("", "v", "c") + + //t.c = u.c or t.d != u.d + want_t_c_eq_u_c := NewComparisonExpr(EQUAL, want_t_c, want_u_c) + want_t_d_ne_u_d := NewComparisonExpr(NOT_EQUAL, want_t_d, want_u_d) + want_t_c_eq_u_c_or_t_d_ne_u_d := NewOrExpr(want_t_c_eq_u_c, want_t_d_ne_u_d) + + want_join_on := NewOnJoinCond(want_t_c_eq_u_c_or_t_d_ne_u_d) + + //u.a != v.a + want_u_a_ne_v_a := NewComparisonExpr(NOT_EQUAL, want_u_a, want_v_a) + want_u_v_join_on := NewOnJoinCond(want_u_a_ne_v_a) + + want_sa_t := gen_want_table("sa", "t") + + want_u := gen_want_table("", "u") + + want_v := gen_want_table("", "v") + + want_t_u_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_sa_t, + Right: want_u, + Cond: want_join_on, + } + + want_u_v_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_t_u_join, + Right: want_v, + Cond: want_u_v_join_on, + } + + want_table_refs := []TableExpr{ + want_u_v_join, + } + + t1wantFrom := &From{Tables: want_table_refs} + + //t.b * u.b + want_t_b_multi_u_b := NewBinaryExpr(MULTI, want_t_b, want_u_b) + + //t.a = u.a + want_t_a_eq_u_a := NewComparisonExpr(EQUAL, want_t_a, want_u_a) + + //t.b > u.b + want_t_b_gt_u_b := NewComparisonExpr(GREAT_THAN, want_t_b, want_u_b) + + //t.a = u.a and t.b > u.b + want_t_a_eq_u_a_logicand_t_b_gt_u_b := NewAndExpr(want_t_a_eq_u_a, want_t_b_gt_u_b) + + want_t_b_plus_u_b_plus_v_b := NewBinaryExpr(PLUS, NewBinaryExpr(PLUS, want_t_b, want_u_b), want_v_b) + + want_paren_t_b_plus_u_b_plus_v_b := NewParenExpr(want_t_b_plus_u_b_plus_v_b) + + //group by t.a,u.a,(t.b+u.b+v.b) + want_groupby := []Expr{ + want_t_a, + want_u_a, + want_paren_t_b_plus_u_b_plus_v_b, + } + + //having t.a = 'jj' and v.c > 1000 + want_tjj := NewNumVal(constant.MakeString("jj"), "", false) + want_t_a_eq_tjj := NewComparisonExpr(EQUAL, want_t_a, want_tjj) + want_v_c_gt_1000 := NewComparisonExpr(GREAT_THAN, want_v_c, NewNumVal(constant.MakeInt64(1000), "", false)) + want_t_a_eq_tjj_and_v_c_gt_1000 := NewAndExpr(want_t_a_eq_tjj, want_v_c_gt_1000) + want_having := NewWhere(want_t_a_eq_tjj_and_v_c_gt_1000) + t1wantFieldList := []SelectExpr{ + { + Expr: want_t_a, + As: "", + }, + { + Expr: want_u_a, + As: "", + }, + { + Expr: want_t_b_multi_u_b, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_t_a_eq_u_a_logicand_t_b_gt_u_b), + Exprs: t1wantFieldList, + GroupBy: want_groupby, + Having: want_having, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t9() (*ast.SelectStmt, *Select) { + /* + SELECT t.a,u.a,t.b * u.b tubb + FROM sa.t join u on t.c = u.c or t.d != u.d + join v on u.a != v.a + where t.a = u.a and t.b > u.b + group by t.a,u.a,(t.b+u.b+v.b) + having t.a = 'jj' and v.c > 1000 + order by t.a asc,u.a desc,v.d asc,tubb + limit 100,2000 + */ + t_a := gen_var_ref("", "t", "a") + t_b := gen_var_ref("", "t", "b") + t_c := gen_var_ref("", "t", "c") + t_d := gen_var_ref("", "t", "d") + + u_a := gen_var_ref("", "u", "a") + u_b := gen_var_ref("", "u", "b") + u_c := gen_var_ref("", "u", "c") + u_d := gen_var_ref("", "u", "d") + + v_a := gen_var_ref("", "v", "a") + v_b := gen_var_ref("", "v", "b") + v_c := gen_var_ref("", "v", "c") + v_d := gen_var_ref("", "v", "d") + tubb := gen_var_ref("", "", "tubb") + + sa_t := gen_table("sa", "t") + + u := gen_table("", "u") + + v := gen_table("", "v") + + t_c_eq_u_c := gen_binary_expr(opcode.EQ, t_c, u_c) + t_d_ne_u_d := gen_binary_expr(opcode.NE, t_d, u_d) + t_c_eq_u_c_or_t_d_ne_u_d := gen_binary_expr(opcode.LogicOr, t_c_eq_u_c, t_d_ne_u_d) + + t_u_onCond := &ast.OnCondition{Expr: t_c_eq_u_c_or_t_d_ne_u_d} + + sa_t_cross_u := &ast.Join{ + Left: sa_t, + Right: u, + Tp: ast.CrossJoin, + On: t_u_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + //u.a != v.a + u_a_ne_v_a := gen_binary_expr(opcode.NE, u_a, v_a) + + u_v_onCond := &ast.OnCondition{Expr: u_a_ne_v_a} + + sa_t_cross_u_cross_v := &ast.Join{ + Left: sa_t_cross_u, + Right: v, + Tp: ast.CrossJoin, + On: u_v_onCond, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: sa_t_cross_u_cross_v} + + t_b_multi_u_b := gen_binary_expr(opcode.Mul, t_b, u_b) + select_fields := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: u_a, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t_b_multi_u_b, + AsName: model.CIStr{"tubb", "tubb"}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: select_fields} + + //t.a = u.a + t_a_eq_u_a := gen_binary_expr(opcode.EQ, t_a, u_a) + + //t.b > u.b + t_b_gt_u_b := gen_binary_expr(opcode.GT, t_b, u_b) + + //t.a = u.a and t.b > u.b + t_a_eq_u_a_and_t_b_gt_u_b := gen_binary_expr(opcode.LogicAnd, t_a_eq_u_a, t_b_gt_u_b) + + //group by t.a,u.a,(t.b+u.b+v.b) + + byitem_t_a := &ast.ByItem{ + Expr: t_a, + Desc: false, + NullOrder: true, + } + + byitem_u_a := &ast.ByItem{ + Expr: u_a, + Desc: false, + NullOrder: true, + } + + t_b_plus_u_b_plus_v_b := gen_binary_expr(opcode.Plus, gen_binary_expr(opcode.Plus, t_b, u_b), v_b) + + paren_t_b_plus_u_b_plus_v_b := &ast.ParenthesesExpr{Expr: t_b_plus_u_b_plus_v_b} + + byitem_t_b_plus_u_b_plus_v_b := &ast.ByItem{ + Expr: paren_t_b_plus_u_b_plus_v_b, + Desc: false, + NullOrder: true, + } + + t_groupby_item := []*ast.ByItem{ + byitem_t_a, + byitem_u_a, + byitem_t_b_plus_u_b_plus_v_b, + } + + t_groupby := &ast.GroupByClause{Items: t_groupby_item} + + //having t.a = 'jj' and v.c > 1000 + + t_jj := ast.NewValueExpr("jj", "", "") + t_a_eq_tjj := gen_binary_expr(opcode.EQ, t_a, t_jj) + v_c_gt_1000 := gen_binary_expr(opcode.GT, v_c, ast.NewValueExpr(1000, "", "")) + t_a_eq_tjj_and_v_c_gt_1000 := gen_binary_expr(opcode.LogicAnd, t_a_eq_tjj, v_c_gt_1000) + + t_having := &ast.HavingClause{Expr: t_a_eq_tjj_and_v_c_gt_1000} + + //order by t.a asc,u.a desc,v.d asc,tubb + byitem_t_a_asc := &ast.ByItem{ + Expr: t_a, + Desc: false, + NullOrder: false, + } + + byitem_u_a_desc := &ast.ByItem{ + Expr: u_a, + Desc: true, + NullOrder: false, + } + + byitem_v_d_asc := &ast.ByItem{ + Expr: v_d, + Desc: false, + NullOrder: false, + } + + byitem_tubb := &ast.ByItem{ + Expr: tubb, + Desc: false, + NullOrder: false, + } + + t_orderby_items := []*ast.ByItem{ + byitem_t_a_asc, + byitem_u_a_desc, + byitem_v_d_asc, + byitem_tubb, + } + + t_orderby := &ast.OrderByClause{ + Items: t_orderby_items, + ForUnion: false, + } + + //limit 100,2000 + t_limit := &ast.Limit{ + Count: ast.NewValueExpr(2000, "", ""), + Offset: ast.NewValueExpr(100, "", ""), + } + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t_a_eq_u_a_and_t_b_gt_u_b, + Fields: t1FieldList, + GroupBy: t_groupby, + Having: t_having, + WindowSpecs: nil, + OrderBy: t_orderby, + Limit: t_limit, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + //========= + + want_t_a, _ := NewUnresolvedName("", "t", "a") + want_t_b, _ := NewUnresolvedName("", "t", "b") + want_t_c, _ := NewUnresolvedName("", "t", "c") + want_t_d, _ := NewUnresolvedName("", "t", "d") + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + want_u_c, _ := NewUnresolvedName("", "u", "c") + want_u_d, _ := NewUnresolvedName("", "u", "d") + + want_v_a, _ := NewUnresolvedName("", "v", "a") + want_v_b, _ := NewUnresolvedName("", "v", "b") + want_v_c, _ := NewUnresolvedName("", "v", "c") + want_v_d, _ := NewUnresolvedName("", "v", "d") + + want_tubb, _ := NewUnresolvedName("", "", "tubb") + + //t.c = u.c or t.d != u.d + want_t_c_eq_u_c := NewComparisonExpr(EQUAL, want_t_c, want_u_c) + want_t_d_ne_u_d := NewComparisonExpr(NOT_EQUAL, want_t_d, want_u_d) + want_t_c_eq_u_c_or_t_d_ne_u_d := NewOrExpr(want_t_c_eq_u_c, want_t_d_ne_u_d) + + want_join_on := NewOnJoinCond(want_t_c_eq_u_c_or_t_d_ne_u_d) + + //u.a != v.a + want_u_a_ne_v_a := NewComparisonExpr(NOT_EQUAL, want_u_a, want_v_a) + want_u_v_join_on := NewOnJoinCond(want_u_a_ne_v_a) + + want_sa_t := gen_want_table("sa", "t") + + want_u := gen_want_table("", "u") + + want_v := gen_want_table("", "v") + + want_t_u_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_sa_t, + Right: want_u, + Cond: want_join_on, + } + + want_u_v_join := &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: want_t_u_join, + Right: want_v, + Cond: want_u_v_join_on, + } + + want_table_refs := []TableExpr{ + want_u_v_join, + } + + t1wantFrom := &From{Tables: want_table_refs} + + //t.b * u.b + want_t_b_multi_u_b := NewBinaryExpr(MULTI, want_t_b, want_u_b) + + //t.a = u.a + want_t_a_eq_u_a := NewComparisonExpr(EQUAL, want_t_a, want_u_a) + + //t.b > u.b + want_t_b_gt_u_b := NewComparisonExpr(GREAT_THAN, want_t_b, want_u_b) + + //t.a = u.a and t.b > u.b + want_t_a_eq_u_a_logicand_t_b_gt_u_b := NewAndExpr(want_t_a_eq_u_a, want_t_b_gt_u_b) + + want_t_b_plus_u_b_plus_v_b := NewBinaryExpr(PLUS, NewBinaryExpr(PLUS, want_t_b, want_u_b), want_v_b) + + want_paren_t_b_plus_u_b_plus_v_b := NewParenExpr(want_t_b_plus_u_b_plus_v_b) + + //group by t.a,u.a,(t.b+u.b+v.b) + want_groupby := []Expr{ + want_t_a, + want_u_a, + want_paren_t_b_plus_u_b_plus_v_b, + } + + //having t.a = 'jj' and v.c > 1000 + want_tjj := NewNumVal(constant.MakeString("jj"), "", false) + want_t_a_eq_tjj := NewComparisonExpr(EQUAL, want_t_a, want_tjj) + num1000 := NewNumVal(constant.MakeInt64(1000), "", false) + want_v_c_gt_1000 := NewComparisonExpr(GREAT_THAN, want_v_c, num1000) + want_t_a_eq_tjj_and_v_c_gt_1000 := NewAndExpr(want_t_a_eq_tjj, want_v_c_gt_1000) + want_having := NewWhere(want_t_a_eq_tjj_and_v_c_gt_1000) + + ////order by t.a asc,u.a desc,v.d asc,tubb + want_orderby := []*Order{ + NewOrder(want_t_a, Ascending, false), + NewOrder(want_u_a, Descending, false), + NewOrder(want_v_d, Ascending, false), + NewOrder(want_tubb, Ascending, false), + } + + //limit 100,2000 + num100 := NewNumVal(constant.MakeInt64(100), "", false) + num2000 := NewNumVal(constant.MakeInt64(2000), "", false) + + want_limit := NewLimit(num100, num2000) + + t1wantFieldList := []SelectExpr{ + { + Expr: want_t_a, + As: "", + }, + { + Expr: want_u_a, + As: "", + }, + { + Expr: want_t_b_multi_u_b, + As: "tubb", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_t_a_eq_u_a_logicand_t_b_gt_u_b), + Exprs: t1wantFieldList, + GroupBy: want_groupby, + Having: want_having, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: want_orderby, + Limit: want_limit, + } + return t1, t1want +} + +func gen_transform_t10() (*ast.SelectStmt, *Select) { + //SELECT * FROM u; + + u := gen_table("", "u") + + t1Join := &ast.Join{ + Left: u, + Right: nil, + Tp: 0, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join} + + t1_wildcard := &ast.WildCardField{} + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: t1_wildcard, + Expr: nil, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + want_u := gen_want_table("", "u") + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: "", + Left: want_u, + Right: nil, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + want_star := StarExpr() + + t1wantFieldList := []SelectExpr{ + { + Expr: want_star, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t11() (*ast.SelectStmt, *Select) { + //SELECT u.* FROM u; + + u := gen_table("", "u") + + t1Join := &ast.Join{ + Left: u, + Right: nil, + Tp: 0, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join} + + t1_wildcard := &ast.WildCardField{Table: model.NewCIStr("u")} + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: t1_wildcard, + Expr: nil, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + want_u := gen_want_table("", "u") + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: "", + Left: want_u, + Right: nil, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + want_star, _ := NewUnresolvedNameWithStar("u") + + t1wantFieldList := []SelectExpr{ + { + Expr: want_star, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t12() (*ast.SelectStmt, *Select) { + /* + SELECT abs(u.a),count(u.b),cast(u.c as char) + from u + */ + + u := gen_table("", "u") + + t1Join := &ast.Join{ + Left: u, + Right: nil, + Tp: 0, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join} + + t1_func_call_agg := []ast.ExprNode{ + gen_var_ref("", "u", "a"), + } + + t1_func_call := &ast.FuncCallExpr{ + Tp: 0, + Schema: model.CIStr{}, + FnName: model.CIStr{"abs", "abs"}, + Args: t1_func_call_agg, + } + + t1_agg_func_agg := []ast.ExprNode{ + gen_var_ref("", "u", "b"), + } + + t1_agg_func := &ast.AggregateFuncExpr{ + F: "count", + Args: t1_agg_func_agg, + Distinct: false, + Order: nil, + } + + t1_func_cast := &ast.FuncCastExpr{ + Expr: gen_var_ref("", "u", "c"), + Tp: types.NewFieldType(253), + FunctionType: 0, + ExplicitCharSet: false, + } + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1_func_call, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1_agg_func, + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: t1_func_cast, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + want_u := gen_want_table("", "u") + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: "", + Left: want_u, + Right: nil, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + want_u_a, _ := NewUnresolvedName("", "u", "a") + want_u_b, _ := NewUnresolvedName("", "u", "b") + want_u_c, _ := NewUnresolvedName("", "u", "c") + + want_abs, _ := NewUnresolvedName("", "abs") + want_call_abs := NewFuncExpr(0, want_abs, []Expr{want_u_a}, nil) + + want_count, _ := NewUnresolvedName("count") + want_call_count := NewFuncExpr(0, want_count, []Expr{want_u_b}, nil) + + want_call_cast := NewCastExpr(want_u_c, TYPE_VARSTRING) + + t1wantFieldList := []SelectExpr{ + { + Expr: want_call_abs, + As: "", + }, + { + Expr: want_call_count, + As: "", + }, + { + Expr: want_call_cast, + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t13() (*ast.SelectStmt, *Select) { + /* + SELECT u.a,(SELECT t.a FROM sa.t,u) + from u + */ + + sub, want_sub := gen_transform_t1() + subExpr := &ast.SubqueryExpr{ + Query: sub, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + u := gen_table("", "u") + + t1Join := &ast.Join{ + Left: u, + Right: nil, + Tp: 0, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join} + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: gen_var_ref("", "u", "a"), + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: subExpr, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + want_u := gen_want_table("", "u") + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: "", + Left: want_u, + Right: nil, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + want_u_a, _ := NewUnresolvedName("", "u", "a") + + t1wantFieldList := []SelectExpr{ + { + Expr: want_u_a, + As: "", + }, + { + Expr: NewSubquery(want_sub.Select, false), + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t14() (*ast.SelectStmt, *Select) { + /* + SELECT u.a,(SELECT t.a FROM sa.t,u) + from u,(SELECT t.a,u.a FROM sa.t,u where t.a = u.a) + */ + + sub, want_sub := gen_transform_t1() + subExpr := &ast.SubqueryExpr{ + Query: sub, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + sub1, want_sub1 := gen_transform_t3() + subExpr1 := &ast.SubqueryExpr{ + Query: sub1, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + u := gen_table("", "u") + + t1Join := &ast.Join{ + Left: u, + Right: nil, + Tp: 0, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + from_sub := &ast.TableSource{ + Source: subExpr1, + AsName: model.CIStr{}, + } + + t1Join2 := &ast.Join{ + Left: t1Join, + Right: from_sub, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join2} + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: gen_var_ref("", "u", "a"), + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: subExpr, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: nil, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + want_u := gen_want_table("", "u") + + from2 := NewAliasedTableExpr(NewSubquery(want_sub1.Select, false), AliasClause{ + Alias: "", + }) + + wantjoin1 := NewJoinTableExpr("", want_u, nil, nil) + + t1wantTableExprArray := []TableExpr{ + &JoinTableExpr{ + JoinType: JOIN_TYPE_CROSS, + Left: wantjoin1, + Right: from2, + Cond: nil, + }, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + want_u_a, _ := NewUnresolvedName("", "u", "a") + + t1wantFieldList := []SelectExpr{ + { + Expr: want_u_a, + As: "", + }, + { + Expr: NewSubquery(want_sub.Select, false), + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: nil, + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func gen_transform_t15() (*ast.SelectStmt, *Select) { + /* + SELECT u.a,(SELECT t.a FROM sa.t,u) + from u,(SELECT t.a,u.a FROM sa.t,u where t.a = u.a) + where (u.a,u.b,u.c) in (SELECT t.a,u.a,t.b * u.b tubb + FROM sa.t join u on t.c = u.c or t.d != u.d + join v on u.a != v.a + where t.a = u.a and t.b > u.b + group by t.a,u.a,(t.b+u.b+v.b) + having t.a = 'jj' and v.c > 1000 + order by t.a asc,u.a desc,v.d asc,tubb + limit 100,2000) + */ + + sub, want_sub := gen_transform_t1() + subExpr := &ast.SubqueryExpr{ + Query: sub, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + sub1, want_sub1 := gen_transform_t3() + subExpr1 := &ast.SubqueryExpr{ + Query: sub1, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + sub2, want_sub2 := gen_transform_t9() + subExpr2 := &ast.SubqueryExpr{ + Query: sub2, + Evaluated: false, + Correlated: false, + MultiRows: false, + Exists: false, + } + + t1row := []ast.ExprNode{ + gen_var_ref("", "u", "a"), + gen_var_ref("", "u", "b"), + gen_var_ref("", "u", "c"), + } + + t1rowExpr := &ast.RowExpr{Values: t1row} + + t1_row_in_expr := &ast.PatternInExpr{ + Expr: t1rowExpr, + List: nil, + Not: false, + Sel: subExpr2, + } + + u := gen_table("", "u") + + t1Join := &ast.Join{ + Left: u, + Right: nil, + Tp: 0, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + from_sub := &ast.TableSource{ + Source: subExpr1, + AsName: model.CIStr{}, + } + + t1Join2 := &ast.Join{ + Left: t1Join, + Right: from_sub, + Tp: ast.CrossJoin, + On: nil, + Using: nil, + NaturalJoin: false, + StraightJoin: false, + ExplicitParens: false, + } + + t1TableRef := &ast.TableRefsClause{TableRefs: t1Join2} + + t1SelectField := []*ast.SelectField{ + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: gen_var_ref("", "u", "a"), + AsName: model.CIStr{}, + Auxiliary: false, + }, + &ast.SelectField{ + Offset: 0, + WildCard: nil, + Expr: subExpr, + AsName: model.CIStr{}, + Auxiliary: false, + }, + } + + t1FieldList := &ast.FieldList{Fields: t1SelectField} + + t1 := &ast.SelectStmt{ + SelectStmtOpts: nil, + Distinct: false, + From: t1TableRef, + Where: t1_row_in_expr, + Fields: t1FieldList, + GroupBy: nil, + Having: nil, + WindowSpecs: nil, + OrderBy: nil, + Limit: nil, + LockInfo: nil, + TableHints: nil, + IsInBraces: false, + QueryBlockOffset: 0, + SelectIntoOpt: nil, + AfterSetOperator: nil, + Kind: 0, + Lists: nil, + } + + // + tp_want_u_a, _ := NewUnresolvedName("", "u", "a") + tp_want_u_b, _ := NewUnresolvedName("", "u", "b") + tp_want_u_c, _ := NewUnresolvedName("", "u", "c") + + want_tuple := []Expr{ + tp_want_u_a, + tp_want_u_b, + tp_want_u_c, + } + + tupleExpr := NewTuple(want_tuple) + + want_in_expr := NewComparisonExpr(IN, tupleExpr, NewSubquery(want_sub2.Select, false)) + + want_joinu := gen_want_table("", "u") + + from2 := NewAliasedTableExpr(NewSubquery(want_sub1.Select, false), AliasClause{ + Alias: "", + }) + + wantjoin1 := NewJoinTableExpr(JOIN_TYPE_CROSS, NewJoinTableExpr("", want_joinu, nil, nil), from2, nil) + + t1wantTableExprArray := []TableExpr{ + //&JoinTableExpr{ + // JoinType: "", + // Left: wantjoin1, + // Right: nil, + // Cond: nil, + //}, + wantjoin1, + } + t1wantFrom := &From{Tables: t1wantTableExprArray} + + want_u_a, _ := NewUnresolvedName("", "u", "a") + + t1wantFieldList := []SelectExpr{ + { + Expr: want_u_a, + As: "", + }, + { + Expr: NewSubquery(want_sub.Select, false), + As: "", + }, + } + + t1wantSelectClause := &SelectClause{ + From: t1wantFrom, + Distinct: false, + Where: NewWhere(want_in_expr), + Exprs: t1wantFieldList, + GroupBy: nil, + Having: nil, + } + + t1want := &Select{ + Select: t1wantSelectClause, + OrderBy: nil, + Limit: nil, + } + return t1, t1want +} + +func Test_transformSelectStmtToSelect(t *testing.T) { + type args struct { + ss *ast.SelectStmt + } + + t1, t1want := gen_transform_t1() + t2, t2want := gen_transform_t2() + t3, t3want := gen_transform_t3() + t4, t4want := gen_transform_t4() + t5, t5want := gen_transform_t5() + t6, t6want := gen_transform_t6() + t7, t7want := gen_transform_t7() + t8, t8want := gen_transform_t8() + t9, t9want := gen_transform_t9() + t10, t10want := gen_transform_t10() + t11, t11want := gen_transform_t11() + t12, t12want := gen_transform_t12() + t13, t13want := gen_transform_t13() + t14, t14want := gen_transform_t14() + t15, t15want := gen_transform_t15() + + tests := []struct { + name string + args args + want *Select + }{ + {"t1", args{t1}, t1want}, + {"t2", args{t2}, t2want}, + {"t3", args{t3}, t3want}, + {"t4", args{t4}, t4want}, + {"t5", args{t5}, t5want}, + {"t6", args{t6}, t6want}, + {"t7", args{t7}, t7want}, + {"t8", args{t8}, t8want}, + {"t9", args{t9}, t9want}, + {"t10", args{t10}, t10want}, + {"t11", args{t11}, t11want}, + {"t12", args{t12}, t12want}, + {"t13", args{t13}, t13want}, + {"t14", args{t14}, t14want}, + {"t15", args{t15}, t15want}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := transformSelectStmtToSelect(tt.args.ss); !reflect.DeepEqual(got, tt.want) { + t.Errorf("transformSelectStmtToSelect() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/sql/tree/types.go b/pkg/sql/tree/types.go new file mode 100644 index 0000000000000000000000000000000000000000..af7e9935c4af44b23415f260920c230a2f850f02 --- /dev/null +++ b/pkg/sql/tree/types.go @@ -0,0 +1,42 @@ +package tree + +import "matrixone/pkg/server" + +type InternalType uint8 + +//sql type +type T struct { + InternalType InternalType +} + +var ( + TYPE_TINY = &T{InternalType: InternalType(server.MYSQL_TYPE_TINY)} + TYPE_SHORT = &T{InternalType: InternalType(server.MYSQL_TYPE_SHORT)} + TYPE_LONG = &T{InternalType: InternalType(server.MYSQL_TYPE_LONG)} + TYPE_FLOAT = &T{InternalType: InternalType(server.MYSQL_TYPE_FLOAT)} + TYPE_DOUBLE = &T{InternalType: InternalType(server.MYSQL_TYPE_DOUBLE)} + TYPE_NULL = &T{InternalType: InternalType(server.MYSQL_TYPE_NULL)} + TYPE_TIMESTAMP = &T{InternalType: InternalType(server.MYSQL_TYPE_TIMESTAMP)} + TYPE_LONGLONG = &T{InternalType: InternalType(server.MYSQL_TYPE_LONGLONG)} + TYPE_INT24 = &T{InternalType: InternalType(server.MYSQL_TYPE_INT24)} + TYPE_DATE = &T{InternalType: InternalType(server.MYSQL_TYPE_DATE)} + TYPE_DURATION = &T{InternalType: InternalType(server.MYSQL_TYPE_TIME)} + TYPE_TIME = &T{InternalType: InternalType(server.MYSQL_TYPE_TIME)} + TYPE_DATETIME = &T{InternalType: InternalType(server.MYSQL_TYPE_DATETIME)} + TYPE_YEAR = &T{InternalType: InternalType(server.MYSQL_TYPE_YEAR)} + TYPE_NEWDATE = &T{InternalType: InternalType(server.MYSQL_TYPE_NEWDATE)} + TYPE_VARCHAR = &T{InternalType: InternalType(server.MYSQL_TYPE_VARCHAR)} + TYPE_BIT = &T{InternalType: InternalType(server.MYSQL_TYPE_BIT)} + + TYPE_BOOL = &T{InternalType: InternalType(server.MYSQL_TYPE_BOOL)} + TYPE_JSON = &T{InternalType: InternalType(server.MYSQL_TYPE_JSON)} + TYPE_ENUM = &T{InternalType: InternalType(server.MYSQL_TYPE_ENUM)} + TYPE_SET = &T{InternalType: InternalType(server.MYSQL_TYPE_SET)} + TYPE_TINY_BLOB = &T{InternalType: InternalType(server.MYSQL_TYPE_TINY_BLOB)} + TYPE_MEDIUM_BLOB = &T{InternalType: InternalType(server.MYSQL_TYPE_MEDIUM_BLOB)} + TYPE_LONG_BLOB = &T{InternalType: InternalType(server.MYSQL_TYPE_LONG_BLOB)} + TYPE_BLOB = &T{InternalType: InternalType(server.MYSQL_TYPE_BLOB)} + TYPE_VARSTRING = &T{InternalType: InternalType(server.MYSQL_TYPE_VAR_STRING)} + TYPE_STRING = &T{InternalType: InternalType(server.MYSQL_TYPE_STRING)} + TYPE_GEOMETRY = &T{InternalType: InternalType(server.MYSQL_TYPE_GEOMETRY)} +)