Skip to content
This repository has been 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
Show file tree
Hide file tree
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
Expand Up @@ -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.|
Expand Down Expand Up @@ -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.|
Expand Down
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"
juanjux marked this conversation as resolved.
Show resolved Hide resolved
"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"
Expand Down
2 changes: 1 addition & 1 deletion sql/analyzer/resolve_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
29 changes: 19 additions & 10 deletions sql/analyzer/validation_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package analyzer
import (
"strings"

errors "gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-errors.v1"
juanjux marked this conversation as resolved.
Show resolved Hide resolved
"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"
Expand Down Expand Up @@ -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()
Expand Down
29 changes: 28 additions & 1 deletion sql/analyzer/validation_rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down