Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Fix validation rule to detect tuples in projections or groupbys #672

Merged
merged 4 commits into from
Apr 23, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@ We support and actively test against certain third-party clients to ensure compa
|`DAYOFWEEK(date)`|Returns the day of the week of the given date.|
|`DAYOFYEAR(date)`|Returns the day of the year of the given date.|
|`FLOOR(number)`|Return the largest integer value that is less than or equal to `number`.|
|`FROM_BASE64(str)`|Decodes the base64-encoded string str.|
|`HOUR(date)`|Returns the hours of the given date.|
|`IFNULL(expr1, expr2)`|If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns expr2.|
|`IS_BINARY(blob)`|Returns whether a BLOB is a binary file or not.|
@@ -110,7 +111,6 @@ We support and actively test against certain third-party clients to ensure compa
|`SUBSTRING(str, pos, [len])`|Return a substring from the provided string starting at `pos` with a length of `len` characters. If no `len` is provided, all characters from `pos` until the end will be taken.|
|`SUM(expr)`|Returns the sum of expr in all rows.|
|`TO_BASE64(str)`|Encodes the string str in base64 format.|
|`FROM_BASE64(str)`|Decodes the base64-encoded string str.|
|`TRIM(str)`|Returns the string str with all spaces removed.|
|`UPPER(str)`|Returns the string str with all characters in upper case.|
|`WEEKDAY(date)`|Returns the weekday of the given date.|
2 changes: 1 addition & 1 deletion sql/analyzer/optimization_rules.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package analyzer

import (
errors "gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
"gopkg.in/src-d/go-mysql-server.v0/sql/plan"
2 changes: 1 addition & 1 deletion sql/analyzer/resolve_columns.go
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import (
"sort"
"strings"

errors "gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
"gopkg.in/src-d/go-mysql-server.v0/sql/plan"
29 changes: 19 additions & 10 deletions sql/analyzer/validation_rules.go
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ package analyzer
import (
"strings"

errors "gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression/function"
@@ -195,27 +195,36 @@ func validateSchema(t *plan.ResolvedTable) error {
return nil
}

func validateProjectTuples(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) {
span, _ := ctx.Span("validate_project_tuples")
defer span.Finish()
func findProjectTuples(n sql.Node) (sql.Node, error) {
if n == nil {
return n, nil
}

switch n := n.(type) {
case *plan.Project:
for i, e := range n.Projections {
case *plan.Project, *plan.GroupBy:
for i, e := range n.(sql.Expressioner).Expressions() {
if sql.IsTuple(e.Type()) {
return nil, ErrProjectTuple.New(i+1, sql.NumColumns(e.Type()))
}
}
case *plan.GroupBy:
for i, e := range n.Aggregate {
if sql.IsTuple(e.Type()) {
return nil, ErrProjectTuple.New(i+1, sql.NumColumns(e.Type()))
default:
for _, ch := range n.Children() {
_, err := findProjectTuples(ch)
if err != nil {
return nil, err
}
}
}

return n, nil
}

func validateProjectTuples(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) {
span, _ := ctx.Span("validate_project_tuples")
defer span.Finish()
return findProjectTuples(n)
}

func validateCaseResultTypes(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) {
span, ctx := ctx.Span("validate_case_result_types")
defer span.Finish()
29 changes: 28 additions & 1 deletion sql/analyzer/validation_rules_test.go
Original file line number Diff line number Diff line change
@@ -235,11 +235,38 @@ func TestValidateProjectTuples(t *testing.T) {
plan.NewProject([]sql.Expression{
expression.NewTuple(
expression.NewLiteral(1, sql.Int64),
expression.NewLiteral(1, sql.Int64),
expression.NewLiteral(2, sql.Int64),
),
}, nil),
false,
},
{
"distinct with a 2 elem tuple inside the project",
plan.NewDistinct(
plan.NewProject([]sql.Expression{
expression.NewTuple(
expression.NewLiteral(1, sql.Int64),
expression.NewLiteral(2, sql.Int64),
),
}, nil)),
false,
},
{
"alias with a tuple",
plan.NewProject(
[]sql.Expression{
expression.NewAlias(
expression.NewTuple(
expression.NewLiteral(1, sql.Int64),
expression.NewLiteral(2, sql.Int64),
),
"foo",
),
},
plan.NewUnresolvedTable("dual", ""),
),
false,
},
{
"groupby with no tuple",
plan.NewGroupBy([]sql.Expression{