diff --git a/CHANGELOG.md b/CHANGELOG.md index fc9d4b8c..b8f969f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## Release v1.8.3 (2019-02-17) + +- Fix the following bugs. + - RETURN statement does not return a value in IF and WHILE statements. + - NOW Function returns different time from the specification in user-defined functions. + ## Release v1.8.2 (2019-02-13) - Fix the following bug. diff --git a/docs/changelog.md b/docs/changelog.md index f38991d6..304a7575 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,12 @@ title: Change Log - csvq # Change Log +## Release v1.8.3 (2019-02-17) + +- Fix the following bugs. + - RETURN statement does not return a value in IF and WHILE statements. + - NOW Function returns different time from the specification in user-defined functions. + ## Release v1.8.2 (2019-02-13) - Fix the following bug. diff --git a/docs/index.md b/docs/index.md index 20305b7c..1880e997 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,8 +13,8 @@ In the multiple operations, you can use variables, cursors, temporary tables, an ## Latest Release -[v1.8.2](https://github.com/mithrandie/csvq/releases/tag/v1.8.2) -: Released on February 13, 2019 +[v1.8.3](https://github.com/mithrandie/csvq/releases/tag/v1.8.3) +: Released on February 17, 2019 [Change Log]({{ '/changelog.html' | relative_url }}) diff --git a/lib/query/filter.go b/lib/query/filter.go index 654076b5..a55f109a 100644 --- a/lib/query/filter.go +++ b/lib/query/filter.go @@ -106,12 +106,14 @@ func (f *Filter) Merge(filter *Filter) { } func (f *Filter) CreateChildScope() *Filter { - return NewFilter( + child := NewFilter( append(VariableScopes{NewVariableMap()}, f.Variables...), append(TemporaryViewScopes{{}}, f.TempViews...), append(CursorScopes{{}}, f.Cursors...), append(UserDefinedFunctionScopes{{}}, f.Functions...), ) + child.Now = f.Now + return child } func (f *Filter) ResetCurrentScope() { diff --git a/lib/query/procedure.go b/lib/query/procedure.go index 436750c1..0dc5eabe 100644 --- a/lib/query/procedure.go +++ b/lib/query/procedure.go @@ -78,7 +78,11 @@ func (proc *Procedure) NewChildProcedure() *Procedure { func (proc *Procedure) ExecuteChild(statements []parser.Statement) (StatementFlow, error) { child := proc.NewChildProcedure() - return child.Execute(statements) + flow, err := child.Execute(statements) + if child.ReturnVal != nil { + proc.ReturnVal = child.ReturnVal + } + return flow, err } func (proc *Procedure) Execute(statements []parser.Statement) (StatementFlow, error) { @@ -486,11 +490,14 @@ func (proc *Procedure) While(stmt parser.While) (StatementFlow, error) { return Error, err } - if f == Break { + switch f { + case Break: return Terminate, nil - } - if f == Exit { + case Exit: return Exit, nil + case Return: + proc.ReturnVal = childProc.ReturnVal + return Return, nil } } return Terminate, nil @@ -526,11 +533,14 @@ func (proc *Procedure) WhileInCursor(stmt parser.WhileInCursor) (StatementFlow, return Error, err } - if f == Break { + switch f { + case Break: return Terminate, nil - } - if f == Exit { + case Exit: return Exit, nil + case Return: + proc.ReturnVal = childProc.ReturnVal + return Return, nil } } diff --git a/lib/query/procedure_test.go b/lib/query/procedure_test.go index 0b373eb3..8aa3e53e 100644 --- a/lib/query/procedure_test.go +++ b/lib/query/procedure_test.go @@ -885,11 +885,12 @@ func TestProcedure_ExecuteStatement(t *testing.T) { } var procedureIfStmtTests = []struct { - Name string - Stmt parser.If - ResultFlow StatementFlow - Result string - Error string + Name string + Stmt parser.If + ResultFlow StatementFlow + ReturnValue value.Primary + Result string + Error string }{ { Name: "If Statement", @@ -983,6 +984,18 @@ var procedureIfStmtTests = []struct { }, Error: "[L:- C:-] field notexist does not exist", }, + { + Name: "If Statement Return Value", + Stmt: parser.If{ + Condition: parser.NewTernaryValue(ternary.TRUE), + Statements: []parser.Statement{ + parser.Return{Value: parser.NewStringValue("1")}, + }, + }, + ResultFlow: Return, + ReturnValue: value.NewString("1"), + Result: "", + }, } func TestProcedure_IfStmt(t *testing.T) { @@ -995,6 +1008,7 @@ func TestProcedure_IfStmt(t *testing.T) { r, w, _ := os.Pipe() Stdout = w + proc.ReturnVal = nil flow, err := proc.IfStmt(v.Stmt) w.Close() @@ -1017,6 +1031,9 @@ func TestProcedure_IfStmt(t *testing.T) { if flow != v.ResultFlow { t.Errorf("%s: result flow = %q, want %q", v.Name, flow, v.ResultFlow) } + if !reflect.DeepEqual(proc.ReturnVal, v.ReturnValue) { + t.Errorf("%s: return = %t, want %t", v.Name, proc.ReturnVal, v.ReturnValue) + } if string(log) != v.Result { t.Errorf("%s: result = %q, want %q", v.Name, string(log), v.Result) } @@ -1198,11 +1215,12 @@ func TestProcedure_Case(t *testing.T) { } var procedureWhileTests = []struct { - Name string - Stmt parser.While - ResultFlow StatementFlow - Result string - Error string + Name string + Stmt parser.While + ResultFlow StatementFlow + ReturnValue value.Primary + Result string + Error string }{ { Name: "While Statement", @@ -1400,6 +1418,31 @@ var procedureWhileTests = []struct { }, Error: "[L:- C:-] field notexist does not exist", }, + { + Name: "While Statement Return Value", + Stmt: parser.While{ + Condition: parser.Comparison{ + LHS: parser.Variable{Name: "while_test"}, + RHS: parser.NewIntegerValueFromString("3"), + Operator: "<", + }, + Statements: []parser.Statement{ + parser.Return{Value: parser.NewStringValue("1")}, + parser.VariableSubstitution{ + Variable: parser.Variable{Name: "while_test"}, + Value: parser.Arithmetic{ + LHS: parser.Variable{Name: "while_test"}, + RHS: parser.NewIntegerValueFromString("1"), + Operator: '+', + }, + }, + parser.Print{Value: parser.Variable{Name: "while_test"}}, + parser.TransactionControl{Token: parser.COMMIT}, + }, + }, + ResultFlow: Return, + ReturnValue: value.NewString("1"), + }, } func TestProcedure_While(t *testing.T) { @@ -1407,6 +1450,7 @@ func TestProcedure_While(t *testing.T) { proc := NewProcedure() for _, v := range procedureWhileTests { + proc.ReturnVal = nil if _, err := proc.Filter.Variables[0].Get(parser.Variable{Name: "while_test"}); err != nil { proc.Filter.Variables[0].Add(parser.Variable{Name: "while_test"}, value.NewInteger(0)) } @@ -1444,6 +1488,9 @@ func TestProcedure_While(t *testing.T) { if flow != v.ResultFlow { t.Errorf("%s: result flow = %q, want %q", v.Name, flow, v.ResultFlow) } + if !reflect.DeepEqual(proc.ReturnVal, v.ReturnValue) { + t.Errorf("%s: return = %t, want %t", v.Name, proc.ReturnVal, v.ReturnValue) + } if string(log) != v.Result { t.Errorf("%s: result = %q, want %q", v.Name, string(log), v.Result) } @@ -1451,11 +1498,12 @@ func TestProcedure_While(t *testing.T) { } var procedureWhileInCursorTests = []struct { - Name string - Stmt parser.WhileInCursor - ResultFlow StatementFlow - Result string - Error string + Name string + Stmt parser.WhileInCursor + ResultFlow StatementFlow + ReturnValue value.Primary + Result string + Error string }{ { Name: "While In Cursor", @@ -1608,6 +1656,23 @@ var procedureWhileInCursorTests = []struct { }, Error: "[L:- C:-] field notexist does not exist", }, + { + Name: "While In Cursor Return Value", + Stmt: parser.WhileInCursor{ + Variables: []parser.Variable{ + {Name: "var1"}, + {Name: "var2"}, + }, + Cursor: parser.Identifier{Literal: "cur"}, + Statements: []parser.Statement{ + parser.Return{Value: parser.NewStringValue("1")}, + parser.Print{Value: parser.Variable{Name: "var1"}}, + parser.TransactionControl{Token: parser.COMMIT}, + }, + }, + ResultFlow: Return, + ReturnValue: value.NewString("1"), + }, } func TestProcedure_WhileInCursor(t *testing.T) { @@ -1655,6 +1720,9 @@ func TestProcedure_WhileInCursor(t *testing.T) { if flow != v.ResultFlow { t.Errorf("%s: result flow = %q, want %q", v.Name, flow, v.ResultFlow) } + if !reflect.DeepEqual(proc.ReturnVal, v.ReturnValue) { + t.Errorf("%s: return = %t, want %t", v.Name, proc.ReturnVal, v.ReturnValue) + } if string(log) != v.Result { t.Errorf("%s: result = %q, want %q", v.Name, string(log), v.Result) } diff --git a/main.go b/main.go index ecf04e34..9b7af09b 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,7 @@ import ( "github.com/urfave/cli" ) -var version = "v1.8.2" +var version = "v1.8.3" func main() { var proc *query.Procedure