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  }