Selaa lähdekoodia

feat: support validate window function in parser (#2164)

Signed-off-by: yisaer <disxiaofei@163.com>
Song Gao 1 vuosi sitten
vanhempi
commit
5c139ef6a6
3 muutettua tiedostoa jossa 72 lisäystä ja 0 poistoa
  1. 42 0
      internal/xsql/parser_srf_test.go
  2. 29 0
      internal/xsql/sqlValidator.go
  3. 1 0
      pkg/ast/visitor.go

+ 42 - 0
internal/xsql/parser_srf_test.go

@@ -20,6 +20,8 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/lf-edge/ekuiper/internal/testx"
 	"github.com/lf-edge/ekuiper/pkg/ast"
 )
@@ -124,3 +126,43 @@ func TestParser_ParserSRFStatement(t *testing.T) {
 		}
 	}
 }
+
+func TestParser_ParserWindowFunctionStatement(t *testing.T) {
+	tests := []struct {
+		s   string
+		err string
+	}{
+		{
+			s:   "select row_number() from demo ",
+			err: "",
+		},
+		{
+			s:   "select * from demo where row_number() > 1",
+			err: "window functions can only be in select fields",
+		},
+		{
+			s:   "select * from demo having row_number() > 1",
+			err: "window functions can only be in select fields",
+		},
+		{
+			s:   "select * from demo group by  row_number()",
+			err: "window functions can only be in select fields",
+		},
+		{
+			s:   "select * from demo left join demo on row_number()",
+			err: "window functions can only be in select fields",
+		},
+		{
+			s:   "select * from demo order by row_number()",
+			err: "window functions can only be in select fields",
+		},
+	}
+	for _, tt := range tests {
+		_, err := NewParser(strings.NewReader(tt.s)).Parse()
+		if len(tt.err) == 0 {
+			require.NoError(t, err)
+		} else {
+			require.Equal(t, tt.err, err.Error())
+		}
+	}
+}

+ 29 - 0
internal/xsql/sqlValidator.go

@@ -39,9 +39,19 @@ func Validate(stmt *ast.SelectStatement) error {
 	if err := validateMultiSRFForbidden("select", stmt.Fields); err != nil {
 		return err
 	}
+	if err := validateWindowFunction(stmt); err != nil {
+		return err
+	}
 	return validateSRFForbidden(stmt)
 }
 
+func validateWindowFunction(stmt *ast.SelectStatement) error {
+	if exists := isWindowFunctionExists(stmt); exists {
+		return fmt.Errorf("window functions can only be in select fields")
+	}
+	return nil
+}
+
 func validateSRFNestedForbidden(clause string, node ast.Node) error {
 	if isSRFNested(node) {
 		return fmt.Errorf("%s clause shouldn't has nested set-returning-functions", clause)
@@ -98,6 +108,25 @@ func isSRFNested(node ast.Node) bool {
 	return srfNested
 }
 
+func isWindowFunctionExists(node ast.Node) bool {
+	exists := false
+	ast.WalkFunc(node, func(n ast.Node) bool {
+		switch f := n.(type) {
+		// skip checking Fields
+		// TODO: support window functions in order by clause lately
+		case ast.Fields:
+			return false
+		case *ast.Call:
+			if f.FuncType == ast.FuncTypeWindow {
+				exists = true
+				return false
+			}
+		}
+		return true
+	})
+	return exists
+}
+
 func isSRFExists(node ast.Node) bool {
 	exists := false
 	ast.WalkFunc(node, func(n ast.Node) bool {

+ 1 - 0
pkg/ast/visitor.go

@@ -40,6 +40,7 @@ func Walk(v Visitor, node Node) {
 		Walk(v, n.Dimensions)
 		Walk(v, n.Having)
 		Walk(v, n.SortFields)
+		Walk(v, n.Limit)
 
 	case Fields:
 		for _, f := range n {