Skip to content

Commit

Permalink
sql: support DESCRIBE table. (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
smola committed Nov 18, 2016
1 parent cf242a8 commit f028104
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ gitql supports a subset of the SQL standard, currently including:
* `ORDER BY` (with `ASC` and `DESC`)
* `LIMIT`
* `SHOW TABLES`
* `DESCRIBE TABLE`

## License

Expand Down
10 changes: 9 additions & 1 deletion sql/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,21 @@ func TestAnalyzer_Analyze(t *testing.T) {
plan.NewUnresolvedTable("mytable"),
)
analyzed, err = a.Analyze(notAnalyzed)
expected := plan.NewProject(
var expected sql.Node = plan.NewProject(
[]sql.Expression{expression.NewGetField(0, sql.Integer, "i")},
table,
)
assert.Nil(err)
assert.Equal(expected, analyzed)

notAnalyzed = plan.NewDescribe(
plan.NewUnresolvedTable("mytable"),
)
analyzed, err = a.Analyze(notAnalyzed)
expected = plan.NewDescribe(table)
assert.Nil(err)
assert.Equal(expected, analyzed)

notAnalyzed = plan.NewProject(
[]sql.Expression{expression.NewStar()},
plan.NewUnresolvedTable("mytable"),
Expand Down
6 changes: 6 additions & 0 deletions sql/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package parse

import (
"fmt"
"regexp"
"strconv"
"strings"

Expand Down Expand Up @@ -34,6 +35,11 @@ func Parse(s string) (sql.Node, error) {
return plan.NewShowTables(&sql.UnresolvedDatabase{}), nil
}

t := regexp.MustCompile(`^describe\s+table\s+(.*)`).FindStringSubmatch(strings.ToLower(s))
if len(t) == 2 && t[1] != "" {
return plan.NewDescribe(plan.NewUnresolvedTable(t[1])), nil
}

stmt, err := sqlparser.Parse(s)
if err != nil {
return nil, err
Expand Down
3 changes: 3 additions & 0 deletions sql/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (
)

var fixtures = map[string]sql.Node{
`DESCRIBE TABLE foo;`: plan.NewDescribe(
plan.NewUnresolvedTable("foo"),
),
`SELECT foo, bar FROM foo;`: plan.NewProject(
[]sql.Expression{
expression.NewUnresolvedColumn("foo"),
Expand Down
4 changes: 4 additions & 0 deletions sql/plan/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ type UnaryNode struct {
Child sql.Node
}

func (n UnaryNode) Resolved() bool {
return n.Child.Resolved()
}

func (n UnaryNode) Children() []sql.Node {
return []sql.Node{n.Child}
}
Expand Down
61 changes: 61 additions & 0 deletions sql/plan/describe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package plan

import (
"io"

"github.com/gitql/gitql/sql"
)

type Describe struct {
UnaryNode
}

func NewDescribe(child sql.Node) *Describe {
return &Describe{UnaryNode{child}}
}

func (d *Describe) Schema() sql.Schema {
return sql.Schema{
sql.Field{
Name: "name",
Type: sql.String,
},
sql.Field{
Name: "type",
Type: sql.String,
},
}
}

func (d *Describe) RowIter() (sql.RowIter, error) {
return &describeIter{schema: d.Child.Schema()}, nil
}

func (d *Describe) TransformUp(f func(sql.Node) sql.Node) sql.Node {
c := d.UnaryNode.Child.TransformUp(f)
n := NewDescribe(c)

return f(n)
}

func (d *Describe) TransformExpressionsUp(f func(sql.Expression) sql.Expression) sql.Node {
c := d.UnaryNode.Child.TransformExpressionsUp(f)
n := NewDescribe(c)

return n
}

type describeIter struct {
schema sql.Schema
i int
}

func (i *describeIter) Next() (sql.Row, error) {
if i.i >= len(i.schema) {
return nil, io.EOF
}

f := i.schema[i.i]
i.i++
return sql.NewMemoryRow(f.Name, f.Type.Name()), nil
}
50 changes: 50 additions & 0 deletions sql/plan/describe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package plan

import (
"io"
"testing"

"github.com/gitql/gitql/mem"
"github.com/gitql/gitql/sql"
"github.com/stretchr/testify/assert"
)

func TestDescribe(t *testing.T) {
assert := assert.New(t)

table := mem.NewTable("test", sql.Schema{
sql.Field{Name: "c1", Type: sql.String},
sql.Field{Name: "c2", Type: sql.Integer},
})

d := NewDescribe(table)
iter, err := d.RowIter()
assert.Nil(err)
assert.NotNil(iter)

n, err := iter.Next()
assert.Nil(err)
assert.Equal(sql.NewMemoryRow("c1", "string"), n)

n, err = iter.Next()
assert.Nil(err)
assert.Equal(sql.NewMemoryRow("c2", "integer"), n)

n, err = iter.Next()
assert.Equal(io.EOF, err)
assert.Nil(n)
}

func TestDescribe_Empty(t *testing.T) {
assert := assert.New(t)

d := NewDescribe(NewUnresolvedTable("test_table"))

iter, err := d.RowIter()
assert.Nil(err)
assert.NotNil(iter)

n, err := iter.Next()
assert.Equal(io.EOF, err)
assert.Nil(n)
}

0 comments on commit f028104

Please sign in to comment.