Skip to content
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

Make DROP/CREATE DATABASE pluggable #7381

Merged
merged 27 commits into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b7400d4
Start of making CREATE DATABASE pluggable
systay Jan 26, 2021
f85d458
use more restrictive type
systay Jan 26, 2021
768719e
use simpler API for the CREATE DB API
systay Jan 26, 2021
9d200e1
Merge remote-tracking branch 'upstream/master' into create-database
systay Feb 22, 2021
668b66f
make it possible to do both create and drop using a plugin
systay Feb 22, 2021
80b184f
adressed PR review
systay Mar 2, 2021
b324b06
Merge remote-tracking branch 'upstream/master' into create-database
systay Mar 2, 2021
7e776c8
[wip] refactored lots of things
systay Mar 3, 2021
cd26ee2
code refactor
harshit-gangal Mar 3, 2021
02e49ce
e2e test fir dbddl plugin
harshit-gangal Mar 3, 2021
a429c60
[wip] implement the dbddl primitive
systay Mar 3, 2021
90b697d
implemented more of the primitive
systay Mar 3, 2021
a32812c
Merge remote-tracking branch 'upstream/master' into create-database
systay Mar 3, 2021
6657063
fix the primitive on create db and implement drop db
harshit-gangal Mar 4, 2021
c77f7c5
e2e test for drop db
harshit-gangal Mar 4, 2021
73eb606
fix dbdddl plugin unit test
harshit-gangal Mar 4, 2021
c8569f0
dbddl: code refactor
harshit-gangal Mar 4, 2021
295f848
added comments to dbddl
harshit-gangal Mar 4, 2021
10daa0e
added comments directive to set query timeout in db ddl primitive
harshit-gangal Mar 4, 2021
131c5f9
added timeout test
harshit-gangal Mar 5, 2021
9a33429
drop database to wait for vschema to be updated
harshit-gangal Mar 8, 2021
afd6e57
fix plan test
harshit-gangal Mar 9, 2021
6a92f2d
on drop database call, check if keyspace is removed from vschema
harshit-gangal Mar 9, 2021
06da2d7
check resolve destination for drop database to see if keyspace is not…
harshit-gangal Mar 10, 2021
00bf410
Merge branch 'master' of github.com:vitessio/vitess into create-database
harshit-gangal Mar 11, 2021
e762d58
make sure to not return error when things worked
systay Mar 11, 2021
6a7f295
watch vschema in drop database to confirm that the keyspace is no lon…
harshit-gangal Mar 11, 2021
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
92 changes: 92 additions & 0 deletions go/vt/vtgate/engine/create_database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
Copyright 2020 The Vitess Authors.
systay marked this conversation as resolved.
Show resolved Hide resolved

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package engine

import (
"strings"

"vitess.io/vitess/go/sqltypes"
querypb "vitess.io/vitess/go/vt/proto/query"
"vitess.io/vitess/go/vt/vtgate/vindexes"
)

var _ Primitive = (*DropCreateDatabase)(nil)

// DropCreateDatabase is just a container around custom database provisioning plugins
// The default behaviour is to just return an error
type DropCreateDatabase struct {
name, verb string
plugin func() error
noInputs
noTxNeeded
}

// CreateDropCreateDatabase creates the engine primitive
func CreateDropCreateDatabase(dbName, verb string, plugin func() error) *DropCreateDatabase {
return &DropCreateDatabase{
name: dbName,
verb: verb,
plugin: plugin,
}
}

// RouteType implements the Primitive interface
func (c *DropCreateDatabase) RouteType() string {
return c.verb + " database"
}

// GetKeyspaceName implements the Primitive interface
func (c *DropCreateDatabase) GetKeyspaceName() string {
return c.name
}

// GetTableName implements the Primitive interface
func (c *DropCreateDatabase) GetTableName() string {
return ""
}

// Execute implements the Primitive interface
func (c *DropCreateDatabase) Execute(VCursor, map[string]*querypb.BindVariable, bool) (*sqltypes.Result, error) {
err := c.plugin()
systay marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}

return &sqltypes.Result{}, nil
systay marked this conversation as resolved.
Show resolved Hide resolved
}

// StreamExecute implements the Primitive interface
func (c *DropCreateDatabase) StreamExecute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error {
res, err := c.Execute(vcursor, bindVars, wantfields)
if err != nil {
return err
}
return callback(res)
}

// GetFields implements the Primitive interface
func (c *DropCreateDatabase) GetFields(VCursor, map[string]*querypb.BindVariable) (*sqltypes.Result, error) {
return &sqltypes.Result{}, nil
}

// description implements the Primitive interface
func (c *DropCreateDatabase) description() PrimitiveDescription {
return PrimitiveDescription{
OperatorType: strings.ToUpper(c.verb + " DATABASE"),
Keyspace: &vindexes.Keyspace{Name: c.name},
}
}
4 changes: 2 additions & 2 deletions go/vt/vtgate/planbuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func buildDBDDLPlan(stmt sqlparser.Statement, vschema ContextVSchema) (engine.Pr
if !ksExists {
return nil, mysql.NewSQLError(mysql.ERDbDropExists, mysql.SSUnknownSQLState, "Can't drop database '%s'; database doesn't exists", ksName)
}
return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "drop database not allowed")
return engine.CreateDropCreateDatabase(dbDDL.DBName, "drop", func() error { return databaseCreator.DropDatabase(dbDDL) }), nil
case *sqlparser.AlterDatabase:
if !ksExists {
return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "Can't alter database '%s'; database doesn't exists", ksName)
Expand All @@ -221,7 +221,7 @@ func buildDBDDLPlan(stmt sqlparser.Statement, vschema ContextVSchema) (engine.Pr
if !dbDDL.IfNotExists && ksExists {
return nil, mysql.NewSQLError(mysql.ERDbCreateExists, mysql.SSUnknownSQLState, "Can't create database '%s'; database exists", ksName)
}
return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "create database not allowed")
return engine.CreateDropCreateDatabase(dbDDL.DBName, "create", func() error { return databaseCreator.CreateDatabase(dbDDL) }), nil
}
return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] unreachable code path: %s", sqlparser.String(dbDDLstmt))
}
Expand Down
44 changes: 44 additions & 0 deletions go/vt/vtgate/planbuilder/create_database_pluggable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package planbuilder

import (
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vterrors"
)

// DropCreateDB is the interface that you need to implement to add a custom CREATE/DROP DATABASE handler
type DropCreateDB interface {
CreateDatabase(ast *sqlparser.CreateDatabase) error
DropDatabase(ast *sqlparser.DropDatabase) error
}

type defaultHandler struct{}

// CreateDatabase implements the DropCreateDB interface
func (defaultHandler) CreateDatabase(*sqlparser.CreateDatabase) error {
return vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "create database not allowed")
}

// DropDatabase implements the DropCreateDB interface
func (defaultHandler) DropDatabase(*sqlparser.DropDatabase) error {
return vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "drop database not allowed")
}

//goland:noinspection GoVarAndConstTypeMayBeOmitted
var databaseCreator DropCreateDB = defaultHandler{}
systay marked this conversation as resolved.
Show resolved Hide resolved
70 changes: 70 additions & 0 deletions go/vt/vtgate/planbuilder/create_database_pluggable_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package planbuilder

import (
"testing"

"vitess.io/vitess/go/vt/sqlparser"

"github.com/stretchr/testify/require"

"vitess.io/vitess/go/vt/vtgate/vindexes"
)

func TestCreateDB(t *testing.T) {
ks := &vindexes.Keyspace{Name: "main"}
vschema := &vschemaWrapper{
v: &vindexes.VSchema{
Keyspaces: map[string]*vindexes.KeyspaceSchema{"main": {Keyspace: ks}},
},
keyspace: ks,
}

// default behaviour
plan, err := TestBuilder("create database test", vschema)
require.NoError(t, err)

_, err = plan.Instructions.Execute(nil, nil, true)
require.EqualError(t, err, "create database not allowed")

// we make sure to restore the state so we don't destabilize other tests
before := databaseCreator
defer func() {
databaseCreator = before
}()

// setting custom behaviour for CREATE DATABASE
databaseCreator = &fakePlugin{}

plan, err = TestBuilder("create database test", vschema)
require.NoError(t, err)
_, err = plan.Instructions.Execute(nil, nil, true)
require.NoError(t, err)
}

type fakePlugin struct{}

// CreateDatabase is a fake
func (*fakePlugin) CreateDatabase(ast *sqlparser.CreateDatabase) error {
return nil
}

// DropDatabase is a fake
func (*fakePlugin) DropDatabase(ast *sqlparser.DropDatabase) error {
return nil
}
36 changes: 33 additions & 3 deletions go/vt/vtgate/planbuilder/testdata/ddl_cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,17 @@

# create db foo
"create database foo"
"create database not allowed"
{
"QueryType": "DDL",
"Original": "create database foo",
"Instructions": {
"OperatorType": "CREATE DATABASE",
"Keyspace": {
"Name": "foo",
"Sharded": false
}
}
}

# create db main
"create database main"
Expand Down Expand Up @@ -128,11 +138,31 @@

# drop db main
"drop database main"
"drop database not allowed"
{
"QueryType": "DDL",
"Original": "drop database main",
"Instructions": {
"OperatorType": "DROP DATABASE",
"Keyspace": {
"Name": "main",
"Sharded": false
}
}
}

# drop db if exists main
"drop database if exists main"
"drop database not allowed"
{
"QueryType": "DDL",
"Original": "drop database if exists main",
"Instructions": {
"OperatorType": "DROP DATABASE",
"Keyspace": {
"Name": "main",
"Sharded": false
}
}
}

# drop db if exists foo
"drop schema if exists foo"
Expand Down