Skip to content

Commit

Permalink
sql: introduce a command to convert a database into a schema
Browse files Browse the repository at this point in the history
Fixes cockroachdb#50885.

This commit introduces a command to convert a database into a user
defined schema under a desired database. This command can be used by
users who are currently emulating a Postgres style set of schemas in
CockroachDB with separate databases.

Release note (sql change): Users can now convert existing databases into
schemas under other databases through the
`ALTER DATABASE ... CONVERT TO SCHEMA UNDER PARENT ...` command. This
command can only be run by `admin` and is only valid for databases that
don't already have any child schemas other than `public`.
  • Loading branch information
rohany committed Aug 19, 2020
1 parent a4286e9 commit 4b4f549
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 5 deletions.
5 changes: 5 additions & 0 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,7 @@ unreserved_keyword ::=
| 'CONFIGURE'
| 'CONSTRAINTS'
| 'CONVERSION'
| 'CONVERT'
| 'COPY'
| 'COVERING'
| 'CREATEROLE'
Expand Down Expand Up @@ -1111,6 +1112,7 @@ alter_sequence_stmt ::=
alter_database_stmt ::=
alter_rename_database_stmt
| alter_zone_database_stmt
| alter_database_to_schema_stmt

alter_range_stmt ::=
alter_zone_range_stmt
Expand Down Expand Up @@ -1522,6 +1524,9 @@ alter_rename_database_stmt ::=
alter_zone_database_stmt ::=
'ALTER' 'DATABASE' database_name set_zone_config

alter_database_to_schema_stmt ::=
'ALTER' 'DATABASE' database_name 'CONVERT' 'TO' 'SCHEMA' 'WITH' 'PARENT' database_name

alter_zone_range_stmt ::=
'ALTER' 'RANGE' zone_name set_zone_config

Expand Down
3 changes: 1 addition & 2 deletions pkg/sql/create_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ func (*createSchemaNode) Next(runParams) (bool, error) { return false, nil }
func (*createSchemaNode) Values() tree.Datums { return tree.Datums{} }
func (n *createSchemaNode) Close(ctx context.Context) {}

// CreateSchema creates a schema. Currently only works in IF NOT EXISTS mode,
// for schemas that do in fact already exist.
// CreateSchema creates a schema.
func (p *planner) CreateSchema(ctx context.Context, n *tree.CreateSchema) (planNode, error) {
return &createSchemaNode{
n: n,
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/drop_cascade.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (d *dropCascadeState) resolveCollectedObjects(
ctx,
tree.ObjectLookupFlags{
// Note we set required to be false here in order to not error out
// if we don't find the object,
// if we don't find the object.
CommonLookupFlags: tree.CommonLookupFlags{Required: false},
RequireMutable: true,
IncludeOffline: true,
Expand Down
66 changes: 66 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/reparent_database
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
statement ok
SET experimental_enable_user_defined_schemas = true;
SET experimental_enable_enums = true;

statement ok
CREATE DATABASE pgdatabase;
CREATE TABLE pgdatabase.t1 (x INT PRIMARY KEY);
CREATE DATABASE pgschema;
CREATE TABLE pgschema.t1 (x INT);
CREATE TABLE pgschema.t2 (x INT);
CREATE TABLE pgschema.t3 (x INT PRIMARY KEY);
ALTER TABLE pgschema.t3 ADD FOREIGN KEY (x) REFERENCES pgdatabase.t1 (x); -- references shouldn't be affected by reparenting.
CREATE TYPE pgschema.typ AS ENUM ('schema');

let $db_id
SELECT id FROM system.namespace WHERE name = 'pgschema'

statement ok
ALTER DATABASE pgschema CONVERT TO SCHEMA WITH PARENT pgdatabase

query I
SELECT * FROM pgdatabase.pgschema.t1

query I
SELECT * FROM pgdatabase.pgschema.t2

query T
SELECT 'schema'::pgdatabase.pgschema.typ
----
schema

statement error pq: insert on table "t3" violates foreign key constraint "fk_x_ref_t1"
INSERT INTO pgdatabase.pgschema.t3 VALUES (1)

# Assert there aren't any namespace entries left with the old parentID.
query T
SELECT name FROM system.namespace WHERE "parentID" = $db_id

# We can't reparent a database that has any child schemas.
statement ok
CREATE DATABASE parent;
USE parent;
CREATE SCHEMA child;
USE test;

statement error pq: cannot convert database with schemas into schema
ALTER DATABASE parent CONVERT TO SCHEMA WITH PARENT pgdatabase

# We can't reparent a database if it causes a name conflict.
statement ok
CREATE DATABASE pgschema

statement error pq: schema "pgschema" already exists
ALTER DATABASE pgschema CONVERT TO SCHEMA WITH PARENT pgdatabase

statement ok
DROP DATABASE pgschema

# We can't convert a database with an invalid schema name into a schema.
statement ok
CREATE DATABASE pg_temp

statement error pq: unacceptable schema name "pg_temp"
ALTER DATABASE pg_temp CONVERT TO SCHEMA WITH PARENT pgdatabase


3 changes: 3 additions & 0 deletions pkg/sql/opaque.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ func buildOpaque(
plan, err = p.RenameColumn(ctx, n)
case *tree.RenameDatabase:
plan, err = p.RenameDatabase(ctx, n)
case *tree.ReparentDatabase:
plan, err = p.ReparentDatabase(ctx, n)
case *tree.RenameIndex:
plan, err = p.RenameIndex(ctx, n)
case *tree.RenameTable:
Expand Down Expand Up @@ -213,6 +215,7 @@ func init() {
&tree.RenameDatabase{},
&tree.RenameIndex{},
&tree.RenameTable{},
&tree.ReparentDatabase{},
&tree.Revoke{},
&tree.RevokeRole{},
&tree.Scatter{},
Expand Down
13 changes: 11 additions & 2 deletions pkg/sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ func (u *sqlSymUnion) executorType() tree.ScheduledJobExecutorType {
%token <str> CHARACTER CHARACTERISTICS CHECK CLOSE
%token <str> CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT
%token <str> COMMITTED COMPACT COMPLETE CONCAT CONCURRENTLY CONFIGURATION CONFIGURATIONS CONFIGURE
%token <str> CONFLICT CONSTRAINT CONSTRAINTS CONTAINS CONVERSION COPY COVERING CREATE CREATEROLE
%token <str> CONFLICT CONSTRAINT CONSTRAINTS CONTAINS CONVERSION CONVERT COPY COVERING CREATE CREATEROLE
%token <str> CROSS CUBE CURRENT CURRENT_CATALOG CURRENT_DATE CURRENT_SCHEMA
%token <str> CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP
%token <str> CURRENT_USER CYCLE
Expand Down Expand Up @@ -714,6 +714,7 @@ func (u *sqlSymUnion) executorType() tree.ScheduledJobExecutorType {

// ALTER DATABASE
%type <tree.Statement> alter_rename_database_stmt
%type <tree.Statement> alter_database_to_schema_stmt
%type <tree.Statement> alter_zone_database_stmt

// ALTER INDEX
Expand Down Expand Up @@ -1383,7 +1384,8 @@ alter_sequence_options_stmt:
// %SeeAlso: WEBDOCS/alter-database.html
alter_database_stmt:
alter_rename_database_stmt
| alter_zone_database_stmt
| alter_zone_database_stmt
| alter_database_to_schema_stmt
// ALTER DATABASE has its error help token here because the ALTER DATABASE
// prefix is spread over multiple non-terminals.
| ALTER DATABASE error // SHOW HELP: ALTER DATABASE
Expand Down Expand Up @@ -6564,6 +6566,12 @@ opt_asc_desc:
$$.val = tree.DefaultDirection
}

alter_database_to_schema_stmt:
ALTER DATABASE database_name CONVERT TO SCHEMA WITH PARENT database_name
{
$$.val = &tree.ReparentDatabase{Name: tree.Name($3), Parent: tree.Name($9)}
}

alter_rename_database_stmt:
ALTER DATABASE database_name RENAME TO database_name
{
Expand Down Expand Up @@ -11138,6 +11146,7 @@ unreserved_keyword:
| CONFIGURE
| CONSTRAINTS
| CONVERSION
| CONVERT
| COPY
| COVERING
| CREATEROLE
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ var _ planNode = &renameColumnNode{}
var _ planNode = &renameDatabaseNode{}
var _ planNode = &renameIndexNode{}
var _ planNode = &renameTableNode{}
var _ planNode = &reparentDatabaseNode{}
var _ planNode = &renderNode{}
var _ planNode = &RevokeRoleNode{}
var _ planNode = &rowCountNode{}
Expand Down Expand Up @@ -237,6 +238,7 @@ var _ planNodeReadingOwnWrites = &changePrivilegesNode{}
var _ planNodeReadingOwnWrites = &dropSchemaNode{}
var _ planNodeReadingOwnWrites = &dropTypeNode{}
var _ planNodeReadingOwnWrites = &refreshMaterializedViewNode{}
var _ planNodeReadingOwnWrites = &reparentDatabaseNode{}
var _ planNodeReadingOwnWrites = &setZoneConfigNode{}

// planNodeRequireSpool serves as marker for nodes whose parent must
Expand Down
Loading

0 comments on commit 4b4f549

Please sign in to comment.