Repository: lf-edge/ekuiper
Pull request #845 (2021-06-19 06:14:05)

fix(sql): subtraction was parsed as negative number
#834 


Patch:
diff --git a/xsql/ast.go b/xsql/ast.go
index ff32ad98..560bb2f8 100644
--- a/xsql/ast.go
+++ b/xsql/ast.go
@@ -1276,6 +1276,17 @@ func (v *ValuerEval) evalBinaryExpr(expr *BinaryExpr) interface{} {
 	case error:
 		return val
 	}
+	// shortcut for bool
+	switch expr.OP {
+	case AND:
+		if bv, ok := lhs.(bool); ok && !bv {
+			return false
+		}
+	case OR:
+		if bv, ok := lhs.(bool); ok && bv {
+			return true
+		}
+	}
 	if isSliceOrArray(lhs) {
 		return v.evalJsonExpr(lhs, expr.OP, expr.RHS)
 	}
diff --git a/xsql/lexical.go b/xsql/lexical.go
index 032cee62..78825cf3 100644
--- a/xsql/lexical.go
+++ b/xsql/lexical.go
@@ -298,9 +298,6 @@ func (s *Scanner) Scan() (tok Token, lit string) {
 			return COMMENT, ""
 		} else if r == '>' {
 			return ARROW, tokens[ARROW]
-		} else if isDigit(r) {
-			s.unread()
-			return s.ScanNumber(false, true)
 		} else if r == '.' {
 			_, _ = s.ScanWhiteSpace()
 			if r1 := s.read(); isDigit(r1) {
diff --git a/xsql/parser.go b/xsql/parser.go
index e59441e6..945b3358 100644
--- a/xsql/parser.go
+++ b/xsql/parser.go
@@ -502,7 +502,7 @@ func (p *Parser) parseUnaryExpr(isSubField bool) (Expr, error) {
 
 	p.unscan()
 
-	tok, lit := p.scanIgnoreWhitespace()
+	tok, lit := p.scanIgnoreWhiteSpaceWithNegativeNum()
 	if tok == CASE {
 		return p.parseCaseExpr()
 	} else if tok == IDENT {
@@ -557,7 +557,7 @@ func (p *Parser) parseUnaryExpr(isSubField bool) (Expr, error) {
 }
 
 func (p *Parser) parseBracketExpr() (Expr, error) {
-	tok2, lit2 := p.scanIgnoreWhitespace()
+	tok2, lit2 := p.scanIgnoreWhiteSpaceWithNegativeNum()
 	if tok2 == RBRACKET {
 		//field[]
 		return &ColonExpr{Start: 0, End: math.MinInt32}, nil
@@ -581,7 +581,7 @@ func (p *Parser) parseBracketExpr() (Expr, error) {
 }
 
 func (p *Parser) parseColonExpr(start int) (Expr, error) {
-	tok, lit := p.scanIgnoreWhitespace()
+	tok, lit := p.scanIgnoreWhiteSpaceWithNegativeNum()
 	if tok == INTEGER {
 		end, err := strconv.Atoi(lit)
 		if err != nil {
@@ -599,6 +599,19 @@ func (p *Parser) parseColonExpr(start int) (Expr, error) {
 	return nil, fmt.Errorf("Found %q, expected right bracket.", lit)
 }
 
+func (p *Parser) scanIgnoreWhiteSpaceWithNegativeNum() (Token, string) {
+	tok, lit := p.scanIgnoreWhitespace()
+	if tok == SUB {
+		_, _ = p.s.ScanWhiteSpace()
+		r := p.s.read()
+		if isDigit(r) {
+			p.s.unread()
+			tok, lit = p.s.ScanNumber(false, true)
+		}
+	}
+	return tok, lit
+}
+
 func (p *Parser) parseAs(f *Field) (*Field, error) {
 	tok, lit := p.scanIgnoreWhitespace()
 	if tok != IDENT {


Test patch:
diff --git a/xsql/parser_test.go b/xsql/parser_test.go
index 5078e6ab..c16ac8a9 100644
--- a/xsql/parser_test.go
+++ b/xsql/parser_test.go
@@ -1395,6 +1395,33 @@ func TestParser_ParseStatement(t *testing.T) {
 				Sources: []Source{&Table{Name: "tbl"}},
 			},
 		},
+		{
+			s: `SELECT count(*)-10 FROM demo`,
+			stmt: &SelectStatement{
+				Fields: []Field{
+					{
+						AName: "",
+						Name:  "",
+						Expr: &BinaryExpr{
+							OP: SUB,
+							LHS: &Call{
+								Name: "count",
+								Args: []Expr{
+									&Wildcard{Token: ASTERISK},
+								},
+							},
+							RHS: &IntegerLiteral{Val: 10},
+						},
+					},
+				},
+				Sources: []Source{&Table{Name: "demo"}},
+			},
+		},
+		{
+			s:    `SELECT -abc FROM demo`,
+			stmt: nil,
+			err:  "found \"-\", expected expression.",
+		},
 	}
 
 	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
diff --git a/xstream/operators/filter_test.go b/xstream/operators/filter_test.go
index 9dc5159f..a33c1e29 100644
--- a/xstream/operators/filter_test.go
+++ b/xstream/operators/filter_test.go
@@ -322,6 +322,32 @@ func TestFilterPlan_Apply(t *testing.T) {
 			},
 			result: nil,
 		},
+		// Test for short circuit. If not, an error would happen
+		{
+			sql: "SELECT abc FROM tbl WHERE abc*2 > 12 AND abc / 0 < 20",
+			data: &xsql.Tuple{
+				Emitter: "tbl",
+				Message: xsql.Message{
+					"abc": int64(6),
+				},
+			},
+			result: nil,
+		},
+		{
+			sql: "SELECT abc FROM tbl WHERE abc*2+3 > 12 OR abc / 0 < 20",
+			data: &xsql.Tuple{
+				Emitter: "tbl",
+				Message: xsql.Message{
+					"abc": int64(6),
+				},
+			},
+			result: &xsql.Tuple{
+				Emitter: "tbl",
+				Message: xsql.Message{
+					"abc": int64(6),
+				},
+			},
+		},
 	}
 
 	fmt.Printf("The test bucket size is %d.\n\n", len(tests))
@@ -445,6 +471,16 @@ func TestFilterPlanError(t *testing.T) {
 			},
 			result: errors.New("run Where error: invalid operation int64(50) = string(v1)"),
 		},
+		{
+			sql: "SELECT abc FROM tbl WHERE abc*2+3 > 12 AND abc / 0 < 20",
+			data: &xsql.Tuple{
+				Emitter: "tbl",
+				Message: xsql.Message{
+					"abc": int64(6),
+				},
+			},
+			result: errors.New("run Where error: divided by zero"),
+		},
 	}
 
 	fmt.Printf("The test bucket size is %d.\n\n", len(tests))