mirror of
https://github.com/grafana/grafana.git
synced 2025-08-02 03:12:13 +08:00
SQL Expressions: Re-implement feature using go-mysql-server (#99521)
* Under feature flag `sqlExpressions` and is experimental * Excluded from arm32 * Will not work with the Query Service yet * Does not have limits in place yet * Does not working with alerting yet * Currently requires "prepare time series" Transform for time series viz --------- Co-authored-by: Sam Jewell <sam.jewell@grafana.com>
This commit is contained in:
136
pkg/expr/sql/parser_allow.go
Normal file
136
pkg/expr/sql/parser_allow.go
Normal file
@ -0,0 +1,136 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/dolthub/vitess/go/vt/sqlparser"
|
||||
)
|
||||
|
||||
// AllowQuery parses the query and checks it against an allow list of allowed SQL nodes
|
||||
// and functions.
|
||||
func AllowQuery(rawSQL string) (bool, error) {
|
||||
s, err := sqlparser.Parse(rawSQL)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error parsing sql: %s", err.Error())
|
||||
}
|
||||
|
||||
walkSubtree := func(node sqlparser.SQLNode) error {
|
||||
err := sqlparser.Walk(func(node sqlparser.SQLNode) (bool, error) {
|
||||
if !allowedNode(node) {
|
||||
if fT, ok := node.(*sqlparser.FuncExpr); ok {
|
||||
return false, fmt.Errorf("blocked function %s - not supported in queries", fT.Name)
|
||||
}
|
||||
return false, fmt.Errorf("blocked node %T - not supported in queries", node)
|
||||
}
|
||||
return true, nil
|
||||
}, node)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse SQL expression: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := walkSubtree(s); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo,nakedret
|
||||
func allowedNode(node sqlparser.SQLNode) (b bool) {
|
||||
b = true // so don't have to return true in every case but default
|
||||
|
||||
switch v := node.(type) {
|
||||
case *sqlparser.FuncExpr:
|
||||
return allowedFunction(v)
|
||||
|
||||
case *sqlparser.AsOf:
|
||||
return
|
||||
|
||||
case *sqlparser.AliasedExpr, *sqlparser.AliasedTableExpr:
|
||||
return
|
||||
|
||||
case *sqlparser.BinaryExpr:
|
||||
return
|
||||
|
||||
case sqlparser.ColIdent, *sqlparser.ColName, sqlparser.Columns:
|
||||
return
|
||||
|
||||
case sqlparser.Comments: // TODO: understand why some are pointer vs not
|
||||
return
|
||||
|
||||
case *sqlparser.CommonTableExpr:
|
||||
return
|
||||
|
||||
case *sqlparser.ComparisonExpr:
|
||||
return
|
||||
|
||||
case *sqlparser.ConvertExpr:
|
||||
return
|
||||
|
||||
case sqlparser.GroupBy:
|
||||
return
|
||||
|
||||
case *sqlparser.IndexHints:
|
||||
return
|
||||
|
||||
case *sqlparser.Into:
|
||||
return
|
||||
|
||||
case *sqlparser.JoinTableExpr, sqlparser.JoinCondition:
|
||||
return
|
||||
|
||||
case *sqlparser.Select, sqlparser.SelectExprs:
|
||||
return
|
||||
|
||||
case *sqlparser.StarExpr:
|
||||
return
|
||||
|
||||
case *sqlparser.SQLVal:
|
||||
return
|
||||
|
||||
case *sqlparser.Limit:
|
||||
return
|
||||
|
||||
case *sqlparser.Order, sqlparser.OrderBy:
|
||||
return
|
||||
|
||||
case *sqlparser.Over:
|
||||
return
|
||||
|
||||
case *sqlparser.Subquery:
|
||||
return
|
||||
|
||||
case sqlparser.TableName, sqlparser.TableExprs, sqlparser.TableIdent:
|
||||
return
|
||||
|
||||
case *sqlparser.With:
|
||||
return
|
||||
|
||||
case *sqlparser.Where:
|
||||
return
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// nolint:gocyclo,nakedret
|
||||
func allowedFunction(f *sqlparser.FuncExpr) (b bool) {
|
||||
b = true // so don't have to return true in every case but default
|
||||
|
||||
switch strings.ToLower(f.Name.String()) {
|
||||
case "sum", "avg", "count", "min", "max":
|
||||
return
|
||||
|
||||
case "coalesce":
|
||||
return
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user