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

Commit

Permalink
Validation rule to detect tuples as distinct argument
Browse files Browse the repository at this point in the history
Signed-off-by: Juanjo Alvarez <juanjo@sourced.tech>
  • Loading branch information
Juanjo Alvarez committed Apr 11, 2019
1 parent be1f7a1 commit ef350d5
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 2 deletions.
8 changes: 8 additions & 0 deletions engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,14 @@ var queries = []struct {
"SELECT FROM_BASE64('YmFy')",
[]sql.Row{{string("bar")}},
},
{
"SELECT DISTINCT 1, 2",
[]sql.Row{{int64(1), int64(2)}},
},
{
"SELECT DISTINCT(1,2)",
[]sql.Row{},
},
}

func TestQueries(t *testing.T) {
Expand Down
3 changes: 2 additions & 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"
Expand Down Expand Up @@ -33,6 +33,7 @@ func optimizeDistinct(ctx *sql.Context, a *Analyzer, node sql.Node) (sql.Node, e
defer span.Finish()

a.Log("optimize distinct, node of type: %T", node)

if node, ok := node.(*plan.Distinct); ok {
var isSorted bool
_, _ = node.TransformUp(func(node sql.Node) (sql.Node, error) {
Expand Down
25 changes: 25 additions & 0 deletions sql/analyzer/resolve_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,31 @@ func checkAliases(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) {
return n, err
}

func checkDistinctNoTuples(ctx *sql.Context, a *Analyzer, node sql.Node) (sql.Node, error) {
span, _ := ctx.Span("no_distinct_tuples")
defer span.Finish()

a.Log("check no tuples as distinct projection, node of type: %T", node)
var err error
if node, ok := node.(*plan.Distinct); ok {
_, err = node.TransformUp(func(node sql.Node) (sql.Node, error) {
project, ok := node.(*plan.Project)
if ok {
for _, col := range project.Projections {
_, ok := col.(expression.Tuple)
if ok {
return node, ErrDistinctTuple.New()
}
}
}

return node, nil
})
}

return node, err
}

func lookForAliasDeclarations(node sql.Expressioner) map[string]struct{} {
var (
aliases = map[string]struct{}{}
Expand Down
20 changes: 20 additions & 0 deletions sql/analyzer/resolve_columns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ func TestMisusedAlias(t *testing.T) {
require.EqualError(err, ErrMisusedAlias.New("alias_i").Error())
}

func TestDistinctNoTuples(t *testing.T) {
require := require.New(t)
f := getRule("check_distinct_no_tuples")

table := mem.NewTable("mytable", sql.Schema{
{Name: "i", Type: sql.Int32},
})

node := plan.NewProject([]sql.Expression{
expression.NewTuple(
expression.NewLiteral(1, sql.Int64),
expression.NewLiteral(2, sql.Int64),
),
}, plan.NewResolvedTable(table))
d := plan.NewDistinct(node)

_, err := f.Apply(sql.NewEmptyContext(), nil, d)
require.EqualError(err, ErrDistinctTuple.New().Error())
}

func TestQualifyColumns(t *testing.T) {
require := require.New(t)
f := getRule("qualify_columns")
Expand Down
2 changes: 2 additions & 0 deletions sql/analyzer/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var OnceBeforeDefault = []Rule{
{"resolve_subqueries", resolveSubqueries},
{"resolve_tables", resolveTables},
{"check_aliases", checkAliases},
{"check_distinct_no_tuples", checkDistinctNoTuples},
}

// OnceAfterDefault contains the rules to be applied just once after the
Expand Down Expand Up @@ -66,4 +67,5 @@ var (
// ErrMisusedAlias is returned when a alias is defined and used in the same projection.
ErrMisusedAlias = errors.NewKind("column %q does not exist in scope, but there is an alias defined in" +
" this projection with that name. Aliases cannot be used in the same projection they're defined in")
ErrDistinctTuple = errors.NewKind("tuple used as DISTINCT argument, remove the ()")
)
2 changes: 1 addition & 1 deletion 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"
"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

0 comments on commit ef350d5

Please sign in to comment.