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

sql/*: implement drop index statement #183

Merged
merged 1 commit into from
Jun 15, 2018
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
26 changes: 15 additions & 11 deletions sql/analyzer/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,25 +776,29 @@ func dedupStrings(in []string) []string {
return result
}

// indexCatalog sets the catalog in the CreateIndex nodes.
// indexCatalog sets the catalog in the CreateIndex and DropIndex nodes.
func indexCatalog(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) {
if !n.Resolved() {
return n, nil
}

ci, ok := n.(*plan.CreateIndex)
if !ok {
return n, nil
}

span, ctx := ctx.Span("index_catalog")
defer span.Finish()

nc := *ci
nc.Catalog = a.Catalog
nc.CurrentDatabase = a.CurrentDatabase

return &nc, nil
switch node := n.(type) {
case *plan.CreateIndex:
nc := *node
nc.Catalog = a.Catalog
nc.CurrentDatabase = a.CurrentDatabase
return &nc, nil
case *plan.DropIndex:
nc := *node
nc.Catalog = a.Catalog
nc.CurrentDatabase = a.CurrentDatabase
return &nc, nil
default:
return n, nil
}
}

func pushdown(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error) {
Expand Down
28 changes: 28 additions & 0 deletions sql/analyzer/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,33 @@ func TestQualifyColumns(t *testing.T) {
require.Equal(expected, result)
}

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

c := sql.NewCatalog()
a := New(c)
a.CurrentDatabase = "foo"

tbl := mem.NewTable("foo", nil)

node, err := f.Apply(sql.NewEmptyContext(), a, plan.NewCreateIndex("", tbl, nil, "", make(map[string]string)))
require.NoError(err)

ci, ok := node.(*plan.CreateIndex)
require.True(ok)
require.Equal(c, ci.Catalog)
require.Equal("foo", ci.CurrentDatabase)

node, err = f.Apply(sql.NewEmptyContext(), a, plan.NewDropIndex("foo", tbl))
require.NoError(err)

di, ok := node.(*plan.DropIndex)
require.True(ok)
require.Equal(c, di.Catalog)
require.Equal("foo", di.CurrentDatabase)
}

func TestReorderProjection(t *testing.T) {
require := require.New(t)
f := getRule("reorder_projection")
Expand Down Expand Up @@ -1656,6 +1683,7 @@ type dummyIndex struct {
var _ sql.Index = (*dummyIndex)(nil)

func (dummyIndex) Database() string { return "" }
func (dummyIndex) Driver() string { return "" }
func (i dummyIndex) ExpressionHashes() []sql.ExpressionHash {
var hashes []sql.ExpressionHash
for _, e := range i.expr {
Expand Down
4 changes: 4 additions & 0 deletions sql/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type Index interface {
// one expression, it means the index has multiple columns indexed. If it's
// just one, it means it may be an expression or a column.
ExpressionHashes() []ExpressionHash
// Driver ID of the index.
Driver() string
}

// AscendIndex is an index that is sorted in ascending order.
Expand Down Expand Up @@ -256,6 +258,8 @@ func (r *IndexRegistry) ReleaseIndex(idx Index) {
func (r *IndexRegistry) Index(db, id string) Index {
r.mut.RLock()
defer r.mut.RUnlock()

r.retainIndex(db, id)
idx := r.indexes[indexKey{db, strings.ToLower(id)}]
if idx != nil && !r.canUseIndex(idx) {
return nil
Expand Down
2 changes: 2 additions & 0 deletions sql/index/pilosa/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ func (idx *pilosaIndex) ExpressionHashes() []sql.ExpressionHash {
return idx.expressions
}

func (pilosaIndex) Driver() string { return DriverID }

type indexLookup struct {
keys []interface{}
indexName string
Expand Down
1 change: 1 addition & 0 deletions sql/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ func (i dummyIdx) Get(...interface{}) (IndexLookup, error) { panic("not implemen
func (i dummyIdx) Has(...interface{}) (bool, error) { panic("not implemented") }
func (i dummyIdx) Database() string { return i.database }
func (i dummyIdx) Table() string { return i.table }
func (i dummyIdx) Driver() string { return "dummy" }

type dummyExpr struct {
index int
Expand Down
40 changes: 40 additions & 0 deletions sql/parse/create_index.go → sql/parse/indexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func parseCreateIndex(s string) (sql.Node, error) {
readKeyValue(config),
skipSpaces,
),
checkEOF,
}

for _, step := range steps {
Expand Down Expand Up @@ -195,6 +196,36 @@ func readValue(val *string) parseFunc {
}
}

func parseDropIndex(str string) (sql.Node, error) {
r := bufio.NewReader(strings.NewReader(str))

var name, table string
steps := []parseFunc{
expect("drop"),
skipSpaces,
expect("index"),
skipSpaces,
readIdent(&name),
skipSpaces,
expect("on"),
skipSpaces,
readIdent(&table),
skipSpaces,
checkEOF,
}

for _, step := range steps {
if err := step(r); err != nil {
return nil, err
}
}

return plan.NewDropIndex(
name,
plan.NewUnresolvedTable(table),
), nil
}

func parseIndexExpr(str string) (sql.Expression, error) {
stmt, err := sqlparser.Parse("SELECT " + str)
if err != nil {
Expand Down Expand Up @@ -368,3 +399,12 @@ func skipSpaces(r *bufio.Reader) error {
}
}
}

func checkEOF(rd *bufio.Reader) error {
r, _, err := rd.ReadRune()
if err == io.EOF {
return nil
}

return errUnexpectedSyntax.New("EOF", r)
}
7 changes: 5 additions & 2 deletions sql/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var (
var (
describeTablesRegex = regexp.MustCompile(`^describe\s+table\s+(.*)`)
createIndexRegex = regexp.MustCompile(`^create\s+index\s+`)
dropIndexRegex = regexp.MustCompile(`^drop\s+index\s+`)
)

// Parse parses the given SQL sentence and returns the corresponding node.
Expand All @@ -48,6 +49,8 @@ func Parse(ctx *sql.Context, s string) (sql.Node, error) {
return parseDescribeTables(lowerQuery)
case createIndexRegex.MatchString(lowerQuery):
return parseCreateIndex(s)
case dropIndexRegex.MatchString(lowerQuery):
return parseDropIndex(s)
}

stmt, err := sqlparser.Parse(s)
Expand Down Expand Up @@ -78,7 +81,7 @@ func convert(ctx *sql.Context, stmt sqlparser.Statement, query string) (sql.Node
case *sqlparser.Insert:
return convertInsert(ctx, n)
case *sqlparser.DDL:
return convertDDL(n, query)
return convertDDL(n)
}
}

Expand Down Expand Up @@ -141,7 +144,7 @@ func convertSelect(ctx *sql.Context, s *sqlparser.Select) (sql.Node, error) {
return node, nil
}

func convertDDL(c *sqlparser.DDL, query string) (sql.Node, error) {
func convertDDL(c *sqlparser.DDL) (sql.Node, error) {
switch c.Action {
case sqlparser.CreateStr:
return convertCreateTable(c)
Expand Down
9 changes: 7 additions & 2 deletions sql/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package parse
import (
"testing"

"github.com/stretchr/testify/require"
"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"

"github.com/stretchr/testify/require"
"gopkg.in/src-d/go-mysql-server.v0/sql"
)

var fixtures = map[string]sql.Node{
Expand Down Expand Up @@ -588,6 +589,10 @@ var fixtures = map[string]sql.Node{
plan.NewUnresolvedTable("baz"),
),
),
`DROP INDEX foo ON bar`: plan.NewDropIndex(
"foo",
plan.NewUnresolvedTable("bar"),
),
}

func TestParse(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions sql/plan/create_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func (i *mockIndex) Get(key ...interface{}) (sql.IndexLookup, error) {
func (i *mockIndex) Has(key ...interface{}) (bool, error) {
panic("unimplemented")
}
func (*mockIndex) Driver() string { return "mock" }

type mockDriver struct {
deleted []string
Expand Down
98 changes: 98 additions & 0 deletions sql/plan/drop_index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package plan

import (
errors "gopkg.in/src-d/go-errors.v1"
"gopkg.in/src-d/go-mysql-server.v0/sql"
)

// ErrIndexNotFound is returned when the index cannot be found.
var ErrIndexNotFound = errors.NewKind("unable to find index %q on table %q of database %q")

// DropIndex is a node to drop an index.
type DropIndex struct {
Name string
Table sql.Node
Catalog *sql.Catalog
CurrentDatabase string
}

// NewDropIndex creates a new DropIndex node.
func NewDropIndex(name string, table sql.Node) *DropIndex {
return &DropIndex{name, table, nil, ""}
}

// Resolved implements the Node interface.
func (d *DropIndex) Resolved() bool { return d.Table.Resolved() }

// Schema implements the Node interface.
func (d *DropIndex) Schema() sql.Schema { return nil }

// Children implements the Node interface.
func (d *DropIndex) Children() []sql.Node { return []sql.Node{d.Table} }

// RowIter implements the Node interface.
func (d *DropIndex) RowIter(ctx *sql.Context) (sql.RowIter, error) {
db, err := d.Catalog.Database(d.CurrentDatabase)
if err != nil {
return nil, err
}

table, ok := d.Table.(sql.Nameable)
if !ok {
return nil, ErrTableNotNameable.New()
}

if _, ok = db.Tables()[table.Name()]; !ok {
return nil, sql.ErrTableNotFound.New(table.Name())
}

index := d.Catalog.Index(db.Name(), d.Name)
if index == nil {
return nil, ErrIndexNotFound.New(d.Name, table.Name(), db.Name())
}
d.Catalog.ReleaseIndex(index)

done, err := d.Catalog.DeleteIndex(db.Name(), d.Name)
if err != nil {
return nil, err
}

driver := d.Catalog.IndexDriver(index.Driver())
if driver == nil {
return nil, ErrInvalidIndexDriver.New(index.Driver())
}

<-done
if err := driver.Delete(index); err != nil {
return nil, err
}

return sql.RowsToRowIter(), nil
}

func (d *DropIndex) String() string {
pr := sql.NewTreePrinter()
_ = pr.WriteNode("DropIndex(%s)", d.Name)
_ = pr.WriteChildren(d.Table.String())
return pr.String()
}

// TransformExpressionsUp implements the Node interface.
func (d *DropIndex) TransformExpressionsUp(fn sql.TransformExprFunc) (sql.Node, error) {
t, err := d.Table.TransformExpressionsUp(fn)
if err != nil {
return nil, err
}

return NewDropIndex(d.Name, t), nil
}

// TransformUp implements the Node interface.
func (d *DropIndex) TransformUp(fn sql.TransformNodeFunc) (sql.Node, error) {
t, err := d.Table.TransformUp(fn)
if err != nil {
return nil, err
}

return fn(NewDropIndex(d.Name, t))
}
Loading