Repository: genjidb/genji (go)

Issue:
parser.ParseQuery panics due to integer divide by zero
`parser.ParseQuery` panics with the following input and stack trace.

```
SELECT*FROM t LIMIT-0%.2
```

<details>
<summary>Stack trace</summary>

```
panic: runtime error: integer divide by zero

goroutine 1 [running]:
github.com/genjidb/genji/document.calculateFloats(0x90, 0x55c760, 0x6dfec0, 0xa0, 0x55bf20, 0xc0000a7c60, 0xc0000a7c25, 0x0, 0x0, 0x900000c000120300, ...)
        /home/runner/work/genji/genji/genji/document/value.go:491 +0x846
github.com/genjidb/genji/document.calculateValues(0xc000111c90, 0x55c760, 0x6dfec0, 0xa0, 0x55bf20, 0xc0000a7c60, 0x25, 0x0, 0x90, 0x55c760, ...)
        /home/runner/work/genji/genji/genji/document/value.go:359 +0x30e
github.com/genjidb/genji/document.Value.Mod(...)
        /home/runner/work/genji/genji/genji/document/value.go:324
github.com/genjidb/genji/sql/query/expr.modOp.Eval(0xc000111c80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40c058, 0x60, ...)
        /home/runner/work/genji/genji/genji/sql/query/expr/arithmeric.go:125 +0x18e
github.com/genjidb/genji/sql/parser.selectConfig.ToTree(0x6a1b14, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /home/runner/work/genji/genji/genji/sql/parser/select.go:261 +0x4ed
github.com/genjidb/genji/sql/parser.(*Parser).parseSelectStatement(0xc000111c20, 0x55, 0x0, 0x0)
        /home/runner/work/genji/genji/genji/sql/parser/select.go:63 +0x44d
github.com/genjidb/genji/sql/parser.(*Parser).ParseStatement(0xc000111c20, 0x55, 0x0, 0x0, 0x0)
        /home/runner/work/genji/genji/genji/sql/parser/parser.go:91 +0x8a2
github.com/genjidb/genji/sql/parser.(*Parser).ParseQuery(0xc000111c20, 0x5be780, 0xc0000a6000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0xc000017860)
        /home/runner/work/genji/genji/genji/sql/parser/parser.go:70 +0x214
github.com/genjidb/genji/sql/parser.ParseQuery(0x5be780, 0xc0000a6000, 0xc000017860, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc00006de70, ...)
        /home/runner/work/genji/genji/genji/sql/parser/parser.go:41 +0x117
github.com/genjidb/genji/fuzz.FuzzParseQuery(0x7f55a2ef1000, 0x18, 0x18, 0x3)
        /home/runner/work/genji/genji/genji/fuzz/sqlparser.go:13 +0xe9
go-fuzz-dep.Main(0xc00006df70, 0x1, 0x1)
        go-fuzz-dep/main.go:36 +0x1ad
main.main()
        github.com/genjidb/genji/fuzz/go.fuzz.main/main.go:15 +0x52
exit status 2
```
</details>

Post-mortem: when evaluating `x % y` expression, y was rounded to the greatest integer value less than or equal to y. We had an explicit check for y ≠ 0 but not after rounding. That is, y ∈ (0; 1) would panic.

Pull request:
Fixes divide by zero panic
Closes #268 

Patch:
diff --git a/document/value.go b/document/value.go
index 47e9aefb..c38c96c4 100644
--- a/document/value.go
+++ b/document/value.go
@@ -483,12 +483,13 @@ func calculateFloats(a, b Value, operator byte) (res Value, err error) {
 
 		return NewDoubleValue(xa / xb), nil
 	case '%':
-		if xb == 0 {
+		mod := math.Mod(xa, xb)
+
+		if math.IsNaN(mod) {
 			return NewNullValue(), nil
 		}
 
-		ia, ib := int64(xa), int64(xb)
-		return NewDoubleValue(float64(ia % ib)), nil
+		return NewDoubleValue(mod), nil
 	case '&':
 		ia, ib := int64(xa), int64(xb)
 		return NewIntegerValue(ia & ib), nil
diff --git a/sql/parser/expr.go b/sql/parser/expr.go
index 2f8ec12a..d658185c 100644
--- a/sql/parser/expr.go
+++ b/sql/parser/expr.go
@@ -84,6 +84,12 @@ func (p *Parser) parseOperator() (func(lhs, rhs expr.Expr) expr.Expr, scanner.To
 		return nil, 0, nil
 	}
 
+	// Ignore currently unused operators.
+	if op == scanner.EQREGEX || op == scanner.NEQREGEX {
+		p.Unscan()
+		return nil, 0, nil
+	}
+
 	switch op {
 	case scanner.EQ:
 		return expr.Eq, op, nil
@@ -585,4 +591,4 @@ func (p *Parser) parseCastExpression() (expr.Expr, error) {
 	}
 
 	return expr.CastFunc{Expr: e, CastAs: tp}, nil
-}
\ No newline at end of file
+}


Test patch:
diff --git a/document/value_test.go b/document/value_test.go
index c0a08a3b..b6750b4a 100644
--- a/document/value_test.go
+++ b/document/value_test.go
@@ -253,7 +253,7 @@ func TestValueMod(t *testing.T) {
 		{"integer(10)%integer(8)", document.NewIntegerValue(10), document.NewIntegerValue(8), document.NewIntegerValue(2), false},
 		{"integer(10)%float64(8)", document.NewIntegerValue(10), document.NewDoubleValue(8), document.NewDoubleValue(2), false},
 		{"int64(maxint)%float64(maxint)", document.NewIntegerValue(math.MaxInt64), document.NewDoubleValue(math.MaxInt64), document.NewDoubleValue(0), false},
-		{"double(> maxint)%int64(100)", document.NewDoubleValue(math.MaxInt64 + 1000), document.NewIntegerValue(100), document.NewDoubleValue(-8), false},
+		{"double(> maxint)%int64(100)", document.NewDoubleValue(math.MaxInt64 + 1000), document.NewIntegerValue(100), document.NewDoubleValue(8), false},
 		{"int64(100)%float64(> maxint)", document.NewIntegerValue(100), document.NewDoubleValue(math.MaxInt64 + 1000), document.NewDoubleValue(100), false},
 		{"integer(120)%text('120')", document.NewIntegerValue(120), document.NewTextValue("120"), document.NewNullValue(), false},
 		{"text('120')%text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
diff --git a/sql/parser/parser_test.go b/sql/parser/parser_test.go
index 0c287762..e7a151e7 100644
--- a/sql/parser/parser_test.go
+++ b/sql/parser/parser_test.go
@@ -4,9 +4,10 @@ import (
 	"context"
 	"testing"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/genjidb/genji/sql/planner"
 	"github.com/genjidb/genji/sql/query"
-	"github.com/stretchr/testify/require"
 )
 
 func TestParserMultiStatement(t *testing.T) {
@@ -43,3 +44,10 @@ func TestParserMultiStatement(t *testing.T) {
 		})
 	}
 }
+
+func TestParserDivideByZero(t *testing.T) {
+	// See https://github.com/genjidb/genji/issues/268
+	require.NotPanics(t, func() {
+		_, _ = ParseQuery(context.Background(), "SELECT * FROM t LIMIT 0 % .5")
+	})
+}