github.com/dolthub/go-mysql-server@v0.18.0/sql/rowexec/show_create_table_test.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package rowexec 16 17 import ( 18 "testing" 19 20 "github.com/dolthub/vitess/go/sqltypes" 21 "github.com/stretchr/testify/require" 22 23 "github.com/dolthub/go-mysql-server/memory" 24 "github.com/dolthub/go-mysql-server/sql" 25 "github.com/dolthub/go-mysql-server/sql/expression" 26 . "github.com/dolthub/go-mysql-server/sql/plan" 27 "github.com/dolthub/go-mysql-server/sql/planbuilder" 28 "github.com/dolthub/go-mysql-server/sql/types" 29 ) 30 31 func TestShowCreateTable(t *testing.T) { 32 var require = require.New(t) 33 34 db := memory.NewDatabase("test") 35 pro := memory.NewDBProvider(db) 36 ctx := newContext(pro) 37 38 schema := sql.Schema{ 39 &sql.Column{Name: "baz", Type: types.Text, Default: nil, Nullable: false, PrimaryKey: true}, 40 &sql.Column{Name: "z`ab", Type: types.Int32, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Int32, true), Nullable: true, PrimaryKey: true}, 41 &sql.Column{Name: "bza", Type: types.Uint64, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Uint64, true), Nullable: true, Comment: "hello"}, 42 &sql.Column{Name: "foo", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 123), Default: nil, Nullable: true}, 43 &sql.Column{Name: "pok", Type: types.MustCreateStringWithDefaults(sqltypes.Char, 123), Default: nil, Nullable: true}, 44 } 45 table := memory.NewTable(db.BaseDatabase, "test-table", sql.NewPrimaryKeySchema(schema), nil) 46 47 showCreateTable, err := NewShowCreateTable(NewResolvedTable(table, nil, nil), false).WithTargetSchema(schema) 48 require.NoError(err) 49 50 rowIter, _ := DefaultBuilder.Build(ctx, showCreateTable, nil) 51 52 row, err := rowIter.Next(ctx) 53 54 require.NoError(err) 55 56 expected := sql.NewRow( 57 table.Name(), 58 "CREATE TABLE `test-table` (\n `baz` text NOT NULL,\n"+ 59 " `z``ab` int DEFAULT '0',\n"+ 60 " `bza` bigint unsigned DEFAULT '0' COMMENT 'hello',\n"+ 61 " `foo` varchar(123),\n"+ 62 " `pok` char(123),\n"+ 63 " PRIMARY KEY (`baz`,`z``ab`)\n"+ 64 ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", 65 ) 66 67 require.Equal(expected, row) 68 69 showCreateTable = NewShowCreateTable(NewResolvedTable(table, nil, nil), true) 70 71 ctx = sql.NewEmptyContext() 72 rowIter, _ = DefaultBuilder.Build(ctx, showCreateTable, nil) 73 74 _, err = rowIter.Next(ctx) 75 require.Error(err) 76 require.True(ErrNotView.Is(err), "wrong error kind") 77 } 78 79 func TestShowCreateTableWithNoPrimaryKey(t *testing.T) { 80 var require = require.New(t) 81 82 db := memory.NewDatabase("test") 83 pro := memory.NewDBProvider(db) 84 ctx := newContext(pro) 85 86 schema := sql.Schema{ 87 &sql.Column{Name: "baz", Type: types.Text, Default: nil, Nullable: false}, 88 &sql.Column{Name: "bza", Type: types.Uint64, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Uint64, true), Nullable: true, Comment: "hello"}, 89 &sql.Column{Name: "foo", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 123), Default: nil, Nullable: true}, 90 &sql.Column{Name: "pok", Type: types.MustCreateStringWithDefaults(sqltypes.Char, 123), Default: nil, Nullable: true}, 91 &sql.Column{Name: "zab", Type: types.Int32, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Int32, true), Nullable: true}, 92 } 93 pkSchema := sql.NewPrimaryKeySchema(schema) 94 table := memory.NewTable(db.BaseDatabase, "test_table", pkSchema, nil) 95 96 showCreateTable, err := NewShowCreateTable(NewResolvedTable(table, nil, nil), false).WithTargetSchema(schema) 97 require.NoError(err) 98 showCreateTable, err = showCreateTable.(*ShowCreateTable).WithPrimaryKeySchema(pkSchema) 99 require.NoError(err) 100 101 rowIter, _ := DefaultBuilder.Build(ctx, showCreateTable, nil) 102 103 row, err := rowIter.Next(ctx) 104 105 require.NoError(err) 106 107 expected := sql.NewRow( 108 table.Name(), 109 "CREATE TABLE `test_table` (\n `baz` text NOT NULL,\n"+ 110 " `bza` bigint unsigned DEFAULT '0' COMMENT 'hello',\n"+ 111 " `foo` varchar(123),\n"+ 112 " `pok` char(123),\n"+ 113 " `zab` int DEFAULT '0'\n"+ 114 ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", 115 ) 116 117 require.Equal(expected, row) 118 } 119 120 func TestShowCreateTableWithPrimaryKey(t *testing.T) { 121 var require = require.New(t) 122 123 db := memory.NewDatabase("test") 124 pro := memory.NewDBProvider(db) 125 ctx := newContext(pro) 126 127 schema := sql.Schema{ 128 &sql.Column{Name: "baz", Type: types.Text, Default: nil, Nullable: false, PrimaryKey: true}, 129 &sql.Column{Name: "bza", Type: types.Uint64, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Uint64, true), Nullable: true, Comment: "hello"}, 130 &sql.Column{Name: "foo", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 123), Default: nil, Nullable: true}, 131 &sql.Column{Name: "pok", Type: types.MustCreateStringWithDefaults(sqltypes.Char, 123), Default: nil, Nullable: true}, 132 &sql.Column{Name: "zab", Type: types.Int32, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Int32, true), Nullable: true, PrimaryKey: true}, 133 } 134 pkSchema := sql.NewPrimaryKeySchema(schema, 4, 0) 135 table := memory.NewTable(db.BaseDatabase, "test-table", pkSchema, nil) 136 137 showCreateTable, err := NewShowCreateTable(NewResolvedTable(table, nil, nil), false).WithTargetSchema(schema) 138 require.NoError(err) 139 showCreateTable, err = showCreateTable.(*ShowCreateTable).WithPrimaryKeySchema(pkSchema) 140 require.NoError(err) 141 142 rowIter, _ := DefaultBuilder.Build(ctx, showCreateTable, nil) 143 144 row, err := rowIter.Next(ctx) 145 146 require.NoError(err) 147 148 expected := sql.NewRow( 149 table.Name(), 150 "CREATE TABLE `test-table` (\n `baz` text NOT NULL,\n"+ 151 " `bza` bigint unsigned DEFAULT '0' COMMENT 'hello',\n"+ 152 " `foo` varchar(123),\n"+ 153 " `pok` char(123),\n"+ 154 " `zab` int DEFAULT '0',\n"+ 155 " PRIMARY KEY (`zab`,`baz`)\n"+ 156 ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", 157 ) 158 159 require.Equal(expected, row) 160 } 161 162 func TestShowCreateTableWithIndexAndForeignKeysAndChecks(t *testing.T) { 163 var require = require.New(t) 164 165 db := memory.NewDatabase("test") 166 pro := memory.NewDBProvider(db) 167 ctx := newContext(pro) 168 169 schema := sql.Schema{ 170 &sql.Column{Name: "baz", Source: "test-table", Type: types.Text, Default: nil, Nullable: false, PrimaryKey: true}, 171 &sql.Column{Name: "zab", Source: "test-table", Type: types.Int32, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Int32, true), Nullable: true, PrimaryKey: true}, 172 &sql.Column{Name: "bza", Source: "test-table", Type: types.Uint64, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Uint64, true), Nullable: true, Comment: "hello"}, 173 &sql.Column{Name: "foo", Source: "test-table", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 123), Default: nil, Nullable: true}, 174 &sql.Column{Name: "pok", Source: "test-table", Type: types.MustCreateStringWithDefaults(sqltypes.Char, 123), Default: nil, Nullable: true}, 175 } 176 table := memory.NewTable(db.BaseDatabase, "test-table", sql.NewPrimaryKeySchema(schema), &memory.ForeignKeyCollection{}) 177 178 require.NoError(table.AddForeignKey(ctx, sql.ForeignKeyConstraint{ 179 Name: "fk1", 180 Database: "testdb", 181 Table: table.Name(), 182 Columns: []string{"baz", "zab"}, 183 ParentDatabase: "testdb", 184 ParentTable: "otherTable", 185 ParentColumns: []string{"a", "b"}, 186 OnUpdate: sql.ForeignKeyReferentialAction_DefaultAction, 187 OnDelete: sql.ForeignKeyReferentialAction_Cascade, 188 IsResolved: true, 189 })) 190 require.NoError(table.AddForeignKey(ctx, sql.ForeignKeyConstraint{ 191 Name: "fk2", 192 Database: "testdb", 193 Table: table.Name(), 194 Columns: []string{"foo"}, 195 ParentDatabase: "testdb", 196 ParentTable: "otherTable", 197 ParentColumns: []string{"b"}, 198 OnUpdate: sql.ForeignKeyReferentialAction_Restrict, 199 OnDelete: sql.ForeignKeyReferentialAction_DefaultAction, 200 IsResolved: true, 201 })) 202 require.NoError(table.AddForeignKey(ctx, sql.ForeignKeyConstraint{ 203 Name: "fk3", 204 Database: "testdb", 205 Table: table.Name(), 206 Columns: []string{"bza"}, 207 ParentDatabase: "testdb", 208 ParentTable: "otherTable", 209 ParentColumns: []string{"c"}, 210 OnUpdate: sql.ForeignKeyReferentialAction_DefaultAction, 211 OnDelete: sql.ForeignKeyReferentialAction_DefaultAction, 212 IsResolved: true, 213 })) 214 215 showCreateTable, err := NewShowCreateTable(NewResolvedTable(table, nil, nil), false).WithTargetSchema(schema) 216 require.NoError(err) 217 218 // This mimics what happens during analysis (indexes get filled in for the table) 219 showCreateTable.(*ShowCreateTable).Indexes = []sql.Index{ 220 &memory.Index{ 221 DB: "testdb", 222 Tbl: table, 223 TableName: table.Name(), 224 Exprs: []sql.Expression{ 225 expression.NewGetFieldWithTable(1, 3, types.Int64, "", "test-table", "foo", true)}, 226 Name: "`qux`", 227 Unique: true, 228 }, 229 &memory.Index{ 230 DB: "testdb", 231 Tbl: table, 232 TableName: "test-table", 233 Name: "zug", 234 Exprs: []sql.Expression{ 235 expression.NewGetFieldWithTable(1, 4, types.Int64, "", "test-table", "pok", true), 236 expression.NewGetFieldWithTable(1, 3, types.Int64, "", "test-table", "foo", true), 237 }, 238 CommentStr: "test comment", 239 }, 240 } 241 242 showCreateTable = showCreateTable.(*ShowCreateTable).WithChecks(sql.CheckConstraints{ 243 { 244 Name: "mycheck", 245 Expr: expression.NewGreaterThan(expression.NewUnresolvedColumn("`zab`"), expression.NewLiteral(int8(0), types.Int8)), 246 Enforced: true, 247 }, 248 }) 249 250 rowIter, _ := DefaultBuilder.Build(ctx, showCreateTable, nil) 251 252 row, err := rowIter.Next(ctx) 253 254 require.NoError(err) 255 256 expected := sql.NewRow( 257 table.Name(), 258 "CREATE TABLE `test-table` (\n `baz` text NOT NULL,\n"+ 259 " `zab` int DEFAULT '0',\n"+ 260 " `bza` bigint unsigned DEFAULT '0' COMMENT 'hello',\n"+ 261 " `foo` varchar(123),\n"+ 262 " `pok` char(123),\n"+ 263 " PRIMARY KEY (`baz`,`zab`),\n"+ 264 " UNIQUE KEY ```qux``` (`foo`),\n"+ 265 " KEY `zug` (`pok`,`foo`) COMMENT 'test comment',\n"+ 266 " CONSTRAINT `fk1` FOREIGN KEY (`baz`,`zab`) REFERENCES `otherTable` (`a`,`b`) ON DELETE CASCADE,\n"+ 267 " CONSTRAINT `fk2` FOREIGN KEY (`foo`) REFERENCES `otherTable` (`b`) ON UPDATE RESTRICT,\n"+ 268 " CONSTRAINT `fk3` FOREIGN KEY (`bza`) REFERENCES `otherTable` (`c`),\n"+ 269 " CONSTRAINT `mycheck` CHECK ((`zab` > 0))\n"+ 270 ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", 271 ) 272 273 require.Equal(expected, row) 274 } 275 276 func TestShowCreateView(t *testing.T) { 277 var require = require.New(t) 278 279 db := memory.NewDatabase("testdb") 280 pro := memory.NewDBProvider(db) 281 ctx := newContext(pro) 282 283 table := memory.NewTable(db.BaseDatabase, "test-table", sql.NewPrimaryKeySchema(sql.Schema{ 284 &sql.Column{Name: "baz", Type: types.Text, Default: nil, Nullable: false, PrimaryKey: true}, 285 &sql.Column{Name: "zab", Type: types.Int32, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Int32, true), Nullable: true, PrimaryKey: true}, 286 &sql.Column{Name: "bza", Type: types.Uint64, Default: planbuilder.MustStringToColumnDefaultValue(ctx, "0", types.Uint64, true), Nullable: true, Comment: "hello"}, 287 &sql.Column{Name: "foo", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 123), Default: nil, Nullable: true}, 288 &sql.Column{Name: "pok", Type: types.MustCreateStringWithDefaults(sqltypes.Char, 123), Default: nil, Nullable: true}, 289 }), nil) 290 291 showCreateTable := NewShowCreateTable( 292 NewSubqueryAlias("myView", "select * from `test-table`", NewResolvedTable(table, nil, nil)), 293 true, 294 ) 295 296 rowIter, _ := DefaultBuilder.Build(ctx, showCreateTable, nil) 297 298 row, err := rowIter.Next(ctx) 299 300 require.Nil(err) 301 302 expected := sql.NewRow( 303 "myView", 304 "CREATE VIEW `myView` AS select * from `test-table`", 305 "utf8mb4", 306 "utf8mb4_0900_bin", 307 ) 308 309 require.Equal(expected, row) 310 }