Skip to content

sql/parse: add support for expression aliases. #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 18, 2016
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
1 change: 1 addition & 0 deletions cmd/gitql/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func (c *CmdQuery) printQuery(schema sql.Schema, iter sql.RowIter) {
w := tablewriter.NewWriter(os.Stdout)
headers := []string{}
for _, f := range schema {
fmt.Printf("HEADER: %s\n", f.Name)
headers = append(headers, f.Name)
}
w.SetHeader(headers)
Expand Down
22 changes: 22 additions & 0 deletions sql/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,28 @@ func TestAnalyzer_Analyze(t *testing.T) {
assert.Nil(err)
assert.Equal(expected, analyzed)

notAnalyzed = plan.NewProject(
[]sql.Expression{
expression.NewAlias(
expression.NewUnresolvedColumn("i"),
"foo",
),
},
plan.NewUnresolvedTable("mytable"),
)
analyzed, err = a.Analyze(notAnalyzed)
expected = plan.NewProject(
[]sql.Expression{
expression.NewAlias(
expression.NewGetField(0, sql.Integer, "i"),
"foo",
),
},
table,
)
assert.Nil(err)
assert.Equal(expected, analyzed)

notAnalyzed = plan.NewProject(
[]sql.Expression{expression.NewUnresolvedColumn("i")},
plan.NewFilter(
Expand Down
34 changes: 28 additions & 6 deletions sql/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,25 @@ func selectToProject(se sqlparser.SelectExprs, child sql.Node) (*plan.Project, e
return plan.NewProject(exprs, child), nil
}

func exprToExpression(e sqlparser.Expr) (sql.Expression, error) {
be, ok := e.(sqlparser.BoolExpr)
if ok {
return boolExprToExpression(be)
}

c, ok := e.(*sqlparser.ComparisonExpr)
if ok {
return comparisonExprToExpression(c)
}

v, ok := e.(sqlparser.ValExpr)
if ok {
return valExprToExpression(v)
}

return nil, errUnsupported(e)
}

func boolExprToExpression(be sqlparser.BoolExpr) (sql.Expression, error) {
switch b := be.(type) {
default:
Expand Down Expand Up @@ -239,6 +258,7 @@ func valExprToExpression(ve sqlparser.ValExpr) (sql.Expression, error) {
//TODO
return expression.NewLiteral(nil, sql.Null), nil
case *sqlparser.ColName:
//TODO: add handling of case sensitiveness.
return expression.NewUnresolvedColumn(v.Name.Lowered()), nil
}
}
Expand All @@ -251,14 +271,16 @@ func selectExprToExpression(se sqlparser.SelectExpr) (sql.Expression, error) {
//TODO: Add support for qualified start.
return expression.NewStar(), nil
case *sqlparser.NonStarExpr:
//TODO: Add support for aliases and functions.
cn, ok := e.Expr.(*sqlparser.ColName)
if !ok {
return nil, errUnsupportedFeature("column aliases or functions")
expr, err := exprToExpression(e.Expr)
if err != nil {
return nil, err
}

if e.As.String() == "" {
return expr, nil
}

//TODO: Add support for column qualifiers.
//TODO: Handle case-sensitiveness when needed.
return expression.NewUnresolvedColumn(cn.Name.Lowered()), nil
return expression.NewAlias(expr, e.As.Lowered()), nil
}
}
9 changes: 9 additions & 0 deletions sql/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ var fixtures = map[string]sql.Node{
},
plan.NewUnresolvedTable("foo"),
),
`SELECT foo AS bar FROM foo;`: plan.NewProject(
[]sql.Expression{
expression.NewAlias(
expression.NewUnresolvedColumn("foo"),
"bar",
),
},
plan.NewUnresolvedTable("foo"),
),
`SELECT foo, bar FROM foo WHERE foo = bar;`: plan.NewProject(
[]sql.Expression{
expression.NewUnresolvedColumn("foo"),
Expand Down
22 changes: 9 additions & 13 deletions sql/plan/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,25 @@ import (
type Project struct {
UnaryNode
expressions []sql.Expression
schema sql.Schema
}

func NewProject(expressions []sql.Expression, child sql.Node) *Project {
schema := sql.Schema{}
childSchema := child.Schema()
for _, expr := range expressions {
for _, field := range childSchema {
if expr.Name() == field.Name {
schema = append(schema, field)
break
}
}
}
return &Project{
UnaryNode: UnaryNode{child},
expressions: expressions,
schema: schema,
}
}

func (p *Project) Schema() sql.Schema {
return p.schema
var s sql.Schema
for _, e := range p.expressions {
f := sql.Field{
Name: e.Name(),
Type: e.Type(),
}
s = append(s, f)
}
return s
}

func (p *Project) Resolved() bool {
Expand Down
13 changes: 12 additions & 1 deletion sql/plan/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,16 @@ func TestProject(t *testing.T) {
require.Nil(row)

p = NewProject(nil, child)
require.Equal(0, len(p.schema))
require.Equal(0, len(p.Schema()))

p = NewProject([]sql.Expression{
expression.NewAlias(
expression.NewGetField(1, sql.String, "col2"),
"foo",
),
}, child)
schema = sql.Schema{
sql.Field{"foo", sql.String},
}
require.Equal(schema, p.Schema())
}