github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/enginetest/branch_control_test.go (about)

     1  // Copyright 2022 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 enginetest
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/dolthub/go-mysql-server/enginetest"
    21  	"github.com/dolthub/go-mysql-server/sql"
    22  	"github.com/dolthub/go-mysql-server/sql/mysql_db"
    23  	"github.com/dolthub/go-mysql-server/sql/plan"
    24  	"github.com/dolthub/go-mysql-server/sql/types"
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  	"gopkg.in/src-d/go-errors.v1"
    28  
    29  	"github.com/dolthub/dolt/go/libraries/doltcore/branch_control"
    30  )
    31  
    32  // BranchControlTest is used to define a test using the branch control system. The root account is used with any queries
    33  // in the SetUpScript.
    34  type BranchControlTest struct {
    35  	Name        string
    36  	SetUpScript []string
    37  	Assertions  []BranchControlTestAssertion
    38  }
    39  
    40  // BranchControlTestAssertion is within a BranchControlTest to assert functionality.
    41  type BranchControlTestAssertion struct {
    42  	User           string
    43  	Host           string
    44  	Query          string
    45  	Expected       []sql.Row
    46  	ExpectedErr    *errors.Kind
    47  	ExpectedErrStr string
    48  }
    49  
    50  // BranchControlBlockTest are tests for quickly verifying that a command is blocked before the appropriate entry is
    51  // added to the "dolt_branch_control" table. The `TestUserSetUpScripts` are automatically run before every test,
    52  // therefore any set up here is essentially appended to `TestUserSetUpScripts`. In addition, the test user is
    53  // `testuser`@`localhost`.
    54  type BranchControlBlockTest struct {
    55  	Name        string
    56  	SetUpScript []string
    57  	Query       string
    58  	ExpectedErr *errors.Kind
    59  	SkipMessage string
    60  }
    61  
    62  // TestUserSetUpScripts creates a user named "testuser@localhost", and grants them privileges on all databases and
    63  // tables. In addition, creates a committed table named "test" with a single value, along with a mirror branch named
    64  // "other".
    65  var TestUserSetUpScripts = []string{
    66  	"DELETE FROM dolt_branch_control WHERE user = '%';",
    67  	"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
    68  	"CREATE USER testuser@localhost;",
    69  	"GRANT ALL ON *.* TO testuser@localhost;",
    70  	"REVOKE SUPER ON *.* FROM testuser@localhost;",
    71  	"CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 BIGINT);",
    72  	"INSERT INTO test VALUES (1, 1);",
    73  	"CALL DOLT_ADD('-A');",
    74  	"CALL DOLT_COMMIT('-m', 'setup commit');",
    75  	"CALL DOLT_BRANCH('other');",
    76  }
    77  
    78  var BranchControlBlockTests = []BranchControlBlockTest{
    79  	{
    80  		Name:        "INSERT",
    81  		Query:       "INSERT INTO test VALUES (2, 2);",
    82  		ExpectedErr: branch_control.ErrIncorrectPermissions,
    83  	},
    84  	{
    85  		Name:        "INSERT on branch db",
    86  		Query:       "INSERT INTO `mydb/other`.test VALUES (2, 2);",
    87  		ExpectedErr: branch_control.ErrIncorrectPermissions,
    88  	},
    89  	{
    90  		Name:        "REPLACE",
    91  		Query:       "REPLACE INTO test VALUES (2, 2);",
    92  		ExpectedErr: branch_control.ErrIncorrectPermissions,
    93  	},
    94  	{
    95  		Name:        "UPDATE",
    96  		Query:       "UPDATE test SET pk = 2;",
    97  		ExpectedErr: branch_control.ErrIncorrectPermissions,
    98  	},
    99  	{
   100  		Name:        "UPDATE on branch db",
   101  		Query:       "UPDATE `mydb/other`.test SET pk = 2;",
   102  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   103  	},
   104  	{
   105  		Name:        "DELETE",
   106  		Query:       "DELETE FROM test WHERE pk >= 0;",
   107  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   108  	},
   109  	{
   110  		Name:        "DELETE from branch table",
   111  		Query:       "DELETE FROM `mydb/other`.test WHERE pk >= 0;",
   112  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   113  	},
   114  	{
   115  		Name:        "TRUNCATE",
   116  		Query:       "TRUNCATE TABLE test;",
   117  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   118  	},
   119  	{
   120  		Name: "ALTER TABLE AUTO_INCREMENT",
   121  		SetUpScript: []string{
   122  			"CREATE TABLE test2(pk BIGINT PRIMARY KEY AUTO_INCREMENT);",
   123  		},
   124  		Query:       "ALTER TABLE test2 AUTO_INCREMENT = 20;",
   125  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   126  	},
   127  	{
   128  		Name:        "ALTER TABLE ADD CHECK",
   129  		Query:       "ALTER TABLE test ADD CONSTRAINT check_1 CHECK (pk > 0);",
   130  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   131  	},
   132  	{
   133  		Name: "ALTER TABLE DROP CHECK",
   134  		SetUpScript: []string{
   135  			"ALTER TABLE test ADD CONSTRAINT check_1 CHECK (pk > 0);",
   136  		},
   137  		Query:       "ALTER TABLE test DROP CHECK check_1;",
   138  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   139  	},
   140  	{
   141  		Name:        "ALTER TABLE ALTER COLUMN SET DEFAULT",
   142  		Query:       "ALTER TABLE test ALTER COLUMN v1 SET DEFAULT (5);",
   143  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   144  	},
   145  	{
   146  		Name: "ALTER TABLE ALTER COLUMN DROP DEFAULT",
   147  		SetUpScript: []string{
   148  			"ALTER TABLE test ALTER COLUMN v1 SET DEFAULT (5);",
   149  		},
   150  		Query:       "ALTER TABLE test ALTER COLUMN v1 DROP DEFAULT;",
   151  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   152  	},
   153  	{
   154  		Name: "ALTER TABLE ADD FOREIGN KEY",
   155  		SetUpScript: []string{
   156  			"ALTER TABLE test ADD INDEX idx_v1 (v1);",
   157  			"CREATE TABLE test2 (pk BIGINT PRIMARY KEY, v1 BIGINT UNIQUE);",
   158  		},
   159  		Query:       "ALTER TABLE test2 ADD CONSTRAINT fk_1 FOREIGN KEY (v1) REFERENCES test (v1);",
   160  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   161  	},
   162  	{
   163  		Name: "ALTER TABLE DROP FOREIGN KEY",
   164  		SetUpScript: []string{
   165  			"ALTER TABLE test ADD INDEX idx_v1 (v1);",
   166  			"CREATE TABLE test2 (pk BIGINT PRIMARY KEY, v1 BIGINT UNIQUE, CONSTRAINT fk_1 FOREIGN KEY (v1) REFERENCES test (v1));",
   167  		},
   168  		Query:       "ALTER TABLE test2 DROP FOREIGN KEY fk_1;",
   169  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   170  	},
   171  	{
   172  		Name:        "ALTER TABLE ADD INDEX",
   173  		Query:       "ALTER TABLE test ADD INDEX idx_v1 (v1);",
   174  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   175  	},
   176  	{
   177  		Name: "ALTER TABLE DROP INDEX",
   178  		SetUpScript: []string{
   179  			"ALTER TABLE test ADD INDEX idx_v1 (v1);",
   180  		},
   181  		Query:       "ALTER TABLE test DROP INDEX idx_v1;",
   182  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   183  	},
   184  	{
   185  		Name: "ALTER TABLE RENAME INDEX",
   186  		SetUpScript: []string{
   187  			"ALTER TABLE test ADD INDEX idx_v1 (v1);",
   188  		},
   189  		Query:       "ALTER TABLE test RENAME INDEX idx_v1 TO idx_v1_new;",
   190  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   191  	},
   192  	{
   193  		Name: "ALTER TABLE ADD PRIMARY KEY",
   194  		SetUpScript: []string{
   195  			"CREATE TABLE test2 (v1 BIGINT, v2 BIGINT);",
   196  		},
   197  		Query:       "ALTER TABLE test2 ADD PRIMARY KEY (v1, v2);",
   198  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   199  	},
   200  	{
   201  		Name:        "ALTER TABLE DROP PRIMARY KEY",
   202  		Query:       "ALTER TABLE test DROP PRIMARY KEY;",
   203  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   204  	},
   205  	{
   206  		Name:        "ALTER TABLE RENAME",
   207  		Query:       "ALTER TABLE test RENAME TO test_new;",
   208  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   209  	},
   210  	{
   211  		Name:        "RENAME TABLE",
   212  		Query:       "RENAME TABLE test TO test_new;",
   213  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   214  	},
   215  	{
   216  		Name:        "ALTER TABLE ADD COLUMN",
   217  		Query:       "ALTER TABLE test ADD COLUMN v2 BIGINT;",
   218  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   219  	},
   220  	{
   221  		Name:        "ALTER TABLE DROP COLUMN",
   222  		Query:       "ALTER TABLE test DROP COLUMN v1;",
   223  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   224  	},
   225  	{
   226  		Name:        "ALTER TABLE CHANGE COLUMN",
   227  		Query:       "ALTER TABLE test CHANGE COLUMN v1 v1_new BIGINT;",
   228  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   229  	},
   230  	{
   231  		Name:        "ALTER TABLE MODIFY COLUMN",
   232  		Query:       "ALTER TABLE test MODIFY COLUMN v1 TINYINT;",
   233  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   234  	},
   235  	{
   236  		Name:        "ALTER TABLE RENAME COLUMN",
   237  		Query:       "ALTER TABLE test RENAME COLUMN v1 TO v1_new;",
   238  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   239  	},
   240  	{
   241  		Name:        "CREATE INDEX",
   242  		Query:       "CREATE INDEX idx_v1 ON test (v1);",
   243  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   244  	},
   245  	{
   246  		Name: "DROP INDEX",
   247  		SetUpScript: []string{
   248  			"CREATE INDEX idx_v1 ON test (v1);",
   249  		},
   250  		Query:       "DROP INDEX idx_v1 ON test;",
   251  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   252  	},
   253  	{
   254  		Name:        "CREATE VIEW",
   255  		Query:       "CREATE VIEW view_1 AS SELECT * FROM TEST;",
   256  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   257  	},
   258  	{
   259  		Name: "DROP VIEW",
   260  		SetUpScript: []string{
   261  			"CREATE VIEW view_1 AS SELECT * FROM TEST;",
   262  		},
   263  		Query:       "DROP VIEW view_1;",
   264  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   265  	},
   266  	{
   267  		Name:        "CREATE TRIGGER",
   268  		Query:       "CREATE TRIGGER trigger_1 BEFORE INSERT ON test FOR EACH ROW SET NEW.v1 = 4;",
   269  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   270  	},
   271  	{
   272  		Name: "DROP TRIGGER",
   273  		SetUpScript: []string{
   274  			"CREATE TRIGGER trigger_1 BEFORE INSERT ON test FOR EACH ROW SET NEW.v1 = 4;",
   275  		},
   276  		Query:       "DROP TRIGGER trigger_1;",
   277  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   278  	},
   279  	{
   280  		Name:        "CREATE TABLE",
   281  		Query:       "CREATE TABLE test2 (pk BIGINT PRIMARY KEY, v1 BIGINT);",
   282  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   283  	},
   284  	{
   285  		Name:        "CREATE TABLE LIKE",
   286  		Query:       "CREATE TABLE test2 LIKE test;",
   287  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   288  	},
   289  	{
   290  		Name:        "CREATE TABLE AS SELECT",
   291  		Query:       "CREATE TABLE test2 AS SELECT * FROM test;",
   292  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   293  	},
   294  	{
   295  		Name:        "DROP TABLE",
   296  		Query:       "DROP TABLE test;",
   297  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   298  	},
   299  	{
   300  		Name:        "CREATE PROCEDURE",
   301  		Query:       "CREATE PROCEDURE testabc(x DOUBLE, y DOUBLE) SELECT x*y;",
   302  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   303  	},
   304  	{
   305  		Name: "DROP PROCEDURE",
   306  		SetUpScript: []string{
   307  			"CREATE PROCEDURE testabc(x DOUBLE, y DOUBLE) SELECT x*y;",
   308  		},
   309  		Query:       "DROP PROCEDURE testabc;",
   310  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   311  	},
   312  	// Dolt Procedures
   313  	{
   314  		Name: "DOLT_ADD",
   315  		SetUpScript: []string{
   316  			"INSERT INTO test VALUES (2, 2);",
   317  		},
   318  		Query:       "CALL DOLT_ADD('-A');",
   319  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   320  	},
   321  	{ // Normal DOLT_BRANCH is tested in BranchControlTests
   322  		Name:        "DOLT_BRANCH Force Copy",
   323  		Query:       "CALL DOLT_BRANCH('-f', '-c', 'main', 'other');",
   324  		ExpectedErr: branch_control.ErrCannotDeleteBranch,
   325  	},
   326  	{
   327  		Name: "DOLT_BRANCH Force Move",
   328  		SetUpScript: []string{
   329  			"INSERT INTO dolt_branch_control VALUES ('%', 'newother', 'testuser', 'localhost', 'write');",
   330  		},
   331  		Query:       "CALL DOLT_BRANCH('-f', '-m', 'other', 'newother');",
   332  		ExpectedErr: branch_control.ErrCannotDeleteBranch,
   333  	},
   334  	{
   335  		Name:        "DOLT_BRANCH Delete",
   336  		Query:       "CALL DOLT_BRANCH('-d', 'other');",
   337  		ExpectedErr: branch_control.ErrCannotDeleteBranch,
   338  	},
   339  	{
   340  		Name:        "DOLT_CLEAN",
   341  		Query:       "CALL DOLT_CLEAN();",
   342  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   343  	},
   344  	{
   345  		Name: "DOLT_COMMIT",
   346  		SetUpScript: []string{
   347  			"INSERT INTO test VALUES (2, 2);",
   348  			"CALL DOLT_ADD('-A');",
   349  		},
   350  		Query:       "CALL DOLT_COMMIT('-m', 'message');",
   351  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   352  	},
   353  	{
   354  		Name:        "DOLT_CONFLICTS_RESOLVE",
   355  		Query:       "CALL DOLT_CONFLICTS_RESOLVE('--ours', '.');",
   356  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   357  	},
   358  	{
   359  		Name: "DOLT_MERGE",
   360  		SetUpScript: []string{
   361  			"INSERT INTO test VALUES (2, 2);",
   362  			"CALL DOLT_ADD('-A');",
   363  			"CALL DOLT_COMMIT('-m', 'message');",
   364  			"CALL DOLT_CHECKOUT('other');",
   365  		},
   366  		Query:       "CALL DOLT_MERGE('main');",
   367  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   368  	},
   369  	{
   370  		Name:        "DOLT_RESET",
   371  		Query:       "CALL DOLT_RESET();",
   372  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   373  	},
   374  	{
   375  		Name:        "DOLT_REVERT",
   376  		Query:       "CALL DOLT_REVERT();",
   377  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   378  	},
   379  	{
   380  		Name:        "DOLT_VERIFY_CONSTRAINTS",
   381  		Query:       "CALL DOLT_VERIFY_CONSTRAINTS('-a');",
   382  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   383  	},
   384  }
   385  
   386  var BranchControlOtherDbBlockTests = []BranchControlBlockTest{
   387  	{
   388  		Name:        "INSERT",
   389  		Query:       "INSERT INTO `mydb/other`.test VALUES (2, 2);",
   390  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   391  	},
   392  	{
   393  		Name:        "REPLACE",
   394  		Query:       "REPLACE INTO `mydb/other`.test VALUES (2, 2);",
   395  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   396  	},
   397  	{
   398  		Name:        "UPDATE",
   399  		Query:       "UPDATE `mydb/other`.test SET pk = 2;",
   400  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   401  	},
   402  	{
   403  		Name:        "DELETE",
   404  		Query:       "DELETE FROM `mydb/other`.test WHERE pk >= 0;",
   405  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   406  	},
   407  	{
   408  		Name:        "TRUNCATE",
   409  		Query:       "TRUNCATE TABLE `mydb/other`.test;",
   410  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   411  	},
   412  	{
   413  		Name: "ALTER TABLE AUTO_INCREMENT",
   414  		SetUpScript: []string{
   415  			"CREATE TABLE `mydb/other`.test2(pk BIGINT PRIMARY KEY AUTO_INCREMENT);",
   416  		},
   417  		Query:       "ALTER TABLE `mydb/other`.test2 AUTO_INCREMENT = 20;",
   418  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   419  	},
   420  	{
   421  		Name:        "ALTER TABLE ADD CHECK",
   422  		Query:       "ALTER TABLE `mydb/other`.test ADD CONSTRAINT check_1 CHECK (pk > 0);",
   423  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   424  	},
   425  	{
   426  		Name: "ALTER TABLE DROP CHECK",
   427  		SetUpScript: []string{
   428  			"ALTER TABLE `mydb/other`.test ADD CONSTRAINT check_1 CHECK (pk > 0);",
   429  		},
   430  		Query:       "ALTER TABLE `mydb/other`.test DROP CHECK check_1;",
   431  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   432  	},
   433  	{
   434  		Name:        "ALTER TABLE ALTER COLUMN SET DEFAULT",
   435  		Query:       "ALTER TABLE `mydb/other`.test ALTER COLUMN v1 SET DEFAULT (5);",
   436  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   437  	},
   438  	{
   439  		Name: "ALTER TABLE ALTER COLUMN DROP DEFAULT",
   440  		SetUpScript: []string{
   441  			"ALTER TABLE `mydb/other`.test ALTER COLUMN v1 SET DEFAULT (5);",
   442  		},
   443  		Query:       "ALTER TABLE `mydb/other`.test ALTER COLUMN v1 DROP DEFAULT;",
   444  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   445  	},
   446  	{
   447  		Name: "ALTER TABLE ADD FOREIGN KEY",
   448  		SetUpScript: []string{
   449  			"ALTER TABLE `mydb/other`.test ADD INDEX idx_v1 (v1);",
   450  			"CREATE TABLE `mydb/other`.test2 (pk BIGINT PRIMARY KEY, v1 BIGINT UNIQUE);",
   451  		},
   452  		Query:       "ALTER TABLE `mydb/other`.test2 ADD CONSTRAINT fk_1 FOREIGN KEY (v1) REFERENCES `mydb/other`.test (v1);",
   453  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   454  	},
   455  	{
   456  		Name: "ALTER TABLE DROP FOREIGN KEY",
   457  		SetUpScript: []string{
   458  			"ALTER TABLE `mydb/other`.test ADD INDEX idx_v1 (v1);",
   459  			"CREATE TABLE `mydb/other`.test2 (pk BIGINT PRIMARY KEY, v1 BIGINT UNIQUE, CONSTRAINT fk_1 FOREIGN KEY (v1) REFERENCES `mydb/other`.test (v1));",
   460  		},
   461  		Query:       "ALTER TABLE `mydb/other`.test2 DROP FOREIGN KEY fk_1;",
   462  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   463  	},
   464  	{
   465  		Name:        "ALTER TABLE ADD INDEX",
   466  		Query:       "ALTER TABLE `mydb/other`.test ADD INDEX idx_v1 (v1);",
   467  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   468  	},
   469  	{
   470  		Name: "ALTER TABLE DROP INDEX",
   471  		SetUpScript: []string{
   472  			"ALTER TABLE `mydb/other`.test ADD INDEX idx_v1 (v1);",
   473  		},
   474  		Query:       "ALTER TABLE `mydb/other`.test DROP INDEX idx_v1;",
   475  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   476  	},
   477  	{
   478  		Name: "ALTER TABLE RENAME INDEX",
   479  		SetUpScript: []string{
   480  			"ALTER TABLE `mydb/other`.test ADD INDEX idx_v1 (v1);",
   481  		},
   482  		Query:       "ALTER TABLE `mydb/other`.test RENAME INDEX idx_v1 TO idx_v1_new;",
   483  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   484  	},
   485  	{
   486  		Name: "ALTER TABLE ADD PRIMARY KEY",
   487  		SetUpScript: []string{
   488  			"CREATE TABLE `mydb/other`.test2 (v1 BIGINT, v2 BIGINT);",
   489  		},
   490  		Query:       "ALTER TABLE `mydb/other`.test2 ADD PRIMARY KEY (v1, v2);",
   491  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   492  	},
   493  	{
   494  		Name:        "ALTER TABLE DROP PRIMARY KEY",
   495  		Query:       "ALTER TABLE `mydb/other`.test DROP PRIMARY KEY;",
   496  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   497  	},
   498  	{
   499  		Name:        "ALTER TABLE RENAME",
   500  		Query:       "ALTER TABLE `mydb/other`.test RENAME TO test_new;",
   501  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   502  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   503  	},
   504  	{
   505  		Name:        "RENAME TABLE",
   506  		Query:       "RENAME TABLE `mydb/other`.test TO test_new;",
   507  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   508  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   509  	},
   510  	{
   511  		Name:        "ALTER TABLE ADD COLUMN",
   512  		Query:       "ALTER TABLE `mydb/other`.test ADD COLUMN v2 BIGINT;",
   513  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   514  	},
   515  	{
   516  		Name:        "ALTER TABLE DROP COLUMN",
   517  		Query:       "ALTER TABLE `mydb/other`.test DROP COLUMN v1;",
   518  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   519  	},
   520  	{
   521  		Name:        "ALTER TABLE CHANGE COLUMN",
   522  		Query:       "ALTER TABLE `mydb/other`.test CHANGE COLUMN v1 v1_new BIGINT;",
   523  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   524  	},
   525  	{
   526  		Name:        "ALTER TABLE MODIFY COLUMN",
   527  		Query:       "ALTER TABLE `mydb/other`.test MODIFY COLUMN v1 TINYINT;",
   528  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   529  	},
   530  	{
   531  		Name:        "ALTER TABLE RENAME COLUMN",
   532  		Query:       "ALTER TABLE `mydb/other`.test RENAME COLUMN v1 TO v1_new;",
   533  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   534  	},
   535  	{
   536  		Name:        "CREATE INDEX",
   537  		Query:       "CREATE INDEX idx_v1 ON `mydb/other`.test (v1);",
   538  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   539  	},
   540  	{
   541  		Name: "DROP INDEX",
   542  		SetUpScript: []string{
   543  			"CREATE INDEX idx_v1 ON `mydb/other`.test (v1);",
   544  		},
   545  		Query:       "DROP INDEX idx_v1 ON `mydb/other`.test;",
   546  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   547  	},
   548  	{
   549  		Name:        "CREATE VIEW",
   550  		Query:       "CREATE VIEW view_1 AS SELECT * FROM `mydb/other`.test;",
   551  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   552  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   553  	},
   554  	{
   555  		Name: "DROP VIEW",
   556  		SetUpScript: []string{
   557  			"CREATE VIEW view_1 AS SELECT * FROM `mydb/other`.test;",
   558  		},
   559  		Query:       "DROP VIEW view_1;",
   560  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   561  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   562  	},
   563  	{
   564  		Name:        "CREATE TRIGGER",
   565  		Query:       "CREATE TRIGGER trigger_1 BEFORE INSERT ON `mydb/other`.test FOR EACH ROW SET NEW.v1 = 4;",
   566  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   567  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   568  	},
   569  	{
   570  		Name: "DROP TRIGGER",
   571  		SetUpScript: []string{
   572  			"CREATE TRIGGER trigger_1 BEFORE INSERT ON `mydb/other`.test FOR EACH ROW SET NEW.v1 = 4;",
   573  		},
   574  		Query:       "DROP TRIGGER `mydb/other`.trigger_1;",
   575  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   576  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   577  	},
   578  	{
   579  		Name:        "CREATE TABLE",
   580  		Query:       "CREATE TABLE `mydb/other`.test2 (pk BIGINT PRIMARY KEY, v1 BIGINT);",
   581  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   582  	},
   583  	{
   584  		Name:        "CREATE TABLE LIKE",
   585  		Query:       "CREATE TABLE `mydb/other`.test2 LIKE `mydb/other`.test;",
   586  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   587  		SkipMessage: "https://github.com/dolthub/dolt/issues/6078",
   588  	},
   589  	{
   590  		Name:        "CREATE TABLE AS SELECT",
   591  		Query:       "CREATE TABLE `mydb/other`.test2 AS SELECT * FROM `mydb/other`.test;",
   592  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   593  	},
   594  	{
   595  		Name:        "DROP TABLE",
   596  		Query:       "DROP TABLE `mydb/other`.test;",
   597  		ExpectedErr: branch_control.ErrIncorrectPermissions,
   598  	},
   599  }
   600  
   601  var BranchControlTests = []BranchControlTest{
   602  	{
   603  		Name: "Namespace entries block",
   604  		SetUpScript: []string{
   605  			"DELETE FROM dolt_branch_control WHERE user = '%';",
   606  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
   607  			"CREATE USER testuser@localhost;",
   608  			"GRANT ALL ON *.* TO testuser@localhost;",
   609  		},
   610  		Assertions: []BranchControlTestAssertion{
   611  			{ // Empty table, all branches are allowed
   612  				User:     "testuser",
   613  				Host:     "localhost",
   614  				Query:    "CALL DOLT_BRANCH('otherbranch1');",
   615  				Expected: []sql.Row{{0}},
   616  			},
   617  			{ // Prefix "other" is now locked by root
   618  				User:  "root",
   619  				Host:  "localhost",
   620  				Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'other%', 'root', 'localhost');",
   621  				Expected: []sql.Row{
   622  					{types.NewOkResult(1)},
   623  				},
   624  			},
   625  			{
   626  				User:        "testuser",
   627  				Host:        "localhost",
   628  				Query:       "CALL DOLT_BRANCH('otherbranch2');",
   629  				ExpectedErr: branch_control.ErrCannotCreateBranch,
   630  			},
   631  			{ // Allow testuser to use the "other" prefix
   632  				User:  "root",
   633  				Host:  "localhost",
   634  				Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'other%', 'testuser', 'localhost');",
   635  				Expected: []sql.Row{
   636  					{types.NewOkResult(1)},
   637  				},
   638  			},
   639  			{
   640  				User:     "testuser",
   641  				Host:     "localhost",
   642  				Query:    "CALL DOLT_BRANCH('otherbranch2');",
   643  				Expected: []sql.Row{{0}},
   644  			},
   645  			{ // Create a longer match, which takes precedence over shorter matches
   646  				User:  "root",
   647  				Host:  "localhost",
   648  				Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'otherbranch%', 'root', 'localhost');",
   649  				Expected: []sql.Row{
   650  					{types.NewOkResult(1)},
   651  				},
   652  			},
   653  			{ // Matches both "other%" and "otherbranch%", but "otherbranch%" wins by being the longer match
   654  				User:        "testuser",
   655  				Host:        "localhost",
   656  				Query:       "CALL DOLT_BRANCH('otherbranch3');",
   657  				ExpectedErr: branch_control.ErrCannotCreateBranch,
   658  			},
   659  			{ // This doesn't match the longer rule, so testuser has access the namespace
   660  				User:     "testuser",
   661  				Host:     "localhost",
   662  				Query:    "CALL DOLT_BRANCH('other3');",
   663  				Expected: []sql.Row{{0}},
   664  			},
   665  			{
   666  				User:  "root",
   667  				Host:  "localhost",
   668  				Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'otherbranch%', 'testuser', 'localhost');",
   669  				Expected: []sql.Row{
   670  					{types.NewOkResult(1)},
   671  				},
   672  			},
   673  			{
   674  				User:     "testuser",
   675  				Host:     "localhost",
   676  				Query:    "CALL DOLT_BRANCH('otherbranch3');",
   677  				Expected: []sql.Row{{0}},
   678  			},
   679  		},
   680  	},
   681  	{
   682  		Name: "Require admin to modify tables",
   683  		SetUpScript: []string{
   684  			"DELETE FROM dolt_branch_control WHERE user = '%';",
   685  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
   686  			"CREATE USER a@localhost;",
   687  			"CREATE USER b@localhost;",
   688  			"GRANT ALL ON *.* TO a@localhost;",
   689  			"REVOKE SUPER ON *.* FROM a@localhost;",
   690  			"GRANT ALL ON *.* TO b@localhost;",
   691  			"REVOKE SUPER ON *.* FROM b@localhost;",
   692  			"INSERT INTO dolt_branch_control VALUES ('%', 'other', 'a', 'localhost', 'write'), ('%', 'prefix%', 'a', 'localhost', 'admin')",
   693  		},
   694  		Assertions: []BranchControlTestAssertion{
   695  			{
   696  				User:        "a",
   697  				Host:        "localhost",
   698  				Query:       "DELETE FROM dolt_branch_control WHERE branch = 'other';",
   699  				ExpectedErr: branch_control.ErrDeletingRow,
   700  			},
   701  			{
   702  				User:        "b",
   703  				Host:        "localhost",
   704  				Query:       "DELETE FROM dolt_branch_control WHERE branch = 'other';",
   705  				ExpectedErr: branch_control.ErrDeletingRow,
   706  			},
   707  			{
   708  				User:        "b",
   709  				Host:        "localhost",
   710  				Query:       "DELETE FROM dolt_branch_control WHERE branch = 'prefix%';",
   711  				ExpectedErr: branch_control.ErrDeletingRow,
   712  			},
   713  			{
   714  				User:  "a",
   715  				Host:  "localhost",
   716  				Query: "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1%', 'b', 'localhost', 'write');",
   717  				Expected: []sql.Row{
   718  					{types.NewOkResult(1)},
   719  				},
   720  			},
   721  			{
   722  				User:        "b",
   723  				Host:        "localhost",
   724  				Query:       "DELETE FROM dolt_branch_control WHERE branch = 'prefix1%';",
   725  				ExpectedErr: branch_control.ErrDeletingRow,
   726  			},
   727  			{ // Must have permission on the new name as well
   728  				User:        "a",
   729  				Host:        "localhost",
   730  				Query:       "UPDATE dolt_branch_control SET branch = 'other1' WHERE branch = 'prefix1%';",
   731  				ExpectedErr: branch_control.ErrUpdatingToRow,
   732  			},
   733  			{
   734  				User:        "b",
   735  				Host:        "localhost",
   736  				Query:       "UPDATE dolt_branch_control SET permissions = 'admin' WHERE branch = 'prefix1%';",
   737  				ExpectedErr: branch_control.ErrUpdatingRow,
   738  			},
   739  			{
   740  				User:  "a",
   741  				Host:  "localhost",
   742  				Query: "UPDATE dolt_branch_control SET permissions = 'admin' WHERE branch = 'prefix1%';",
   743  				Expected: []sql.Row{
   744  					{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}},
   745  				},
   746  			},
   747  			{
   748  				User:  "b",
   749  				Host:  "localhost",
   750  				Query: "DELETE FROM dolt_branch_control WHERE branch = 'prefix1%';",
   751  				Expected: []sql.Row{
   752  					{types.NewOkResult(1)},
   753  				},
   754  			},
   755  			{
   756  				User:        "b",
   757  				Host:        "localhost",
   758  				Query:       "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1%', 'b', 'localhost', 'admin');",
   759  				ExpectedErr: branch_control.ErrInsertingAccessRow,
   760  			},
   761  			{ // Since "a" has admin on "prefix%", they can also insert into the namespace table
   762  				User:  "a",
   763  				Host:  "localhost",
   764  				Query: "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'prefix___', 'a', 'localhost');",
   765  				Expected: []sql.Row{
   766  					{types.NewOkResult(1)},
   767  				},
   768  			},
   769  			{
   770  				User:        "b",
   771  				Host:        "localhost",
   772  				Query:       "INSERT INTO dolt_branch_namespace_control VALUES ('%', 'prefix', 'b', 'localhost');",
   773  				ExpectedErr: branch_control.ErrInsertingNamespaceRow,
   774  			},
   775  			{
   776  				User:  "a",
   777  				Host:  "localhost",
   778  				Query: "UPDATE dolt_branch_namespace_control SET branch = 'prefix%';",
   779  				Expected: []sql.Row{
   780  					{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}},
   781  				},
   782  			},
   783  			{
   784  				User:        "a",
   785  				Host:        "localhost",
   786  				Query:       "UPDATE dolt_branch_namespace_control SET branch = 'other';",
   787  				ExpectedErr: branch_control.ErrUpdatingToRow,
   788  			},
   789  			{
   790  				User:        "b",
   791  				Host:        "localhost",
   792  				Query:       "DELETE FROM dolt_branch_namespace_control WHERE branch = 'prefix%';",
   793  				ExpectedErr: branch_control.ErrDeletingRow,
   794  			},
   795  			{
   796  				User:        "b",
   797  				Host:        "localhost",
   798  				Query:       "UPDATE dolt_branch_namespace_control SET branch = 'anything';",
   799  				ExpectedErr: branch_control.ErrUpdatingRow,
   800  			},
   801  		},
   802  	},
   803  	{
   804  		Name: "Deleting entries works",
   805  		SetUpScript: []string{
   806  			"DELETE FROM dolt_branch_control WHERE user = '%';",
   807  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
   808  			"CREATE TABLE test (pk BIGINT PRIMARY KEY);",
   809  			"CREATE USER testuser@localhost;",
   810  			"GRANT ALL ON *.* TO testuser@localhost;",
   811  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'testuser', 'localhost_1', 'write');",
   812  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'testuser', 'localhost_2', 'write');",
   813  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'testuser', 'localhost', 'write');",
   814  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'testuser', 'localhost_3', 'write');",
   815  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'testuser', 'localhost_4', 'write');",
   816  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'testuser', 'localhost_5', 'write');",
   817  			"DELETE FROM dolt_branch_control WHERE host IN ('localhost_2', 'localhost_3');",
   818  		},
   819  		Assertions: []BranchControlTestAssertion{
   820  			{
   821  				User:  "testuser",
   822  				Host:  "localhost",
   823  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
   824  				Expected: []sql.Row{
   825  					{"%", "%", "testuser", "localhost_1", "write"},
   826  					{"%", "%", "testuser", "localhost", "write"},
   827  					{"%", "%", "testuser", "localhost_4", "write"},
   828  					{"%", "%", "testuser", "localhost_5", "write"},
   829  				},
   830  			},
   831  			{
   832  				User:  "testuser",
   833  				Host:  "localhost",
   834  				Query: "INSERT INTO test VALUES (1);",
   835  				Expected: []sql.Row{
   836  					{types.NewOkResult(1)},
   837  				},
   838  			},
   839  			{
   840  				User:  "root",
   841  				Host:  "localhost",
   842  				Query: "DELETE FROM dolt_branch_control WHERE host = 'localhost_5';",
   843  				Expected: []sql.Row{
   844  					{types.NewOkResult(1)},
   845  				},
   846  			},
   847  			{
   848  				User:  "testuser",
   849  				Host:  "localhost",
   850  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
   851  				Expected: []sql.Row{
   852  					{"%", "%", "testuser", "localhost_1", "write"},
   853  					{"%", "%", "testuser", "localhost", "write"},
   854  					{"%", "%", "testuser", "localhost_4", "write"},
   855  				},
   856  			},
   857  			{
   858  				User:  "testuser",
   859  				Host:  "localhost",
   860  				Query: "INSERT INTO test VALUES (2);",
   861  				Expected: []sql.Row{
   862  					{types.NewOkResult(1)},
   863  				},
   864  			},
   865  			{
   866  				User:  "root",
   867  				Host:  "localhost",
   868  				Query: "DELETE FROM dolt_branch_control WHERE host = 'localhost_1';",
   869  				Expected: []sql.Row{
   870  					{types.NewOkResult(1)},
   871  				},
   872  			},
   873  			{
   874  				User:  "testuser",
   875  				Host:  "localhost",
   876  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
   877  				Expected: []sql.Row{
   878  					{"%", "%", "testuser", "localhost", "write"},
   879  					{"%", "%", "testuser", "localhost_4", "write"},
   880  				},
   881  			},
   882  			{
   883  				User:  "testuser",
   884  				Host:  "localhost",
   885  				Query: "INSERT INTO test VALUES (3);",
   886  				Expected: []sql.Row{
   887  					{types.NewOkResult(1)},
   888  				},
   889  			},
   890  			{
   891  				User:  "root",
   892  				Host:  "localhost",
   893  				Query: "DELETE FROM dolt_branch_control WHERE host = 'localhost_4';",
   894  				Expected: []sql.Row{
   895  					{types.NewOkResult(1)},
   896  				},
   897  			},
   898  			{
   899  				User:  "testuser",
   900  				Host:  "localhost",
   901  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
   902  				Expected: []sql.Row{
   903  					{"%", "%", "testuser", "localhost", "write"},
   904  				},
   905  			},
   906  			{
   907  				User:  "testuser",
   908  				Host:  "localhost",
   909  				Query: "INSERT INTO test VALUES (4);",
   910  				Expected: []sql.Row{
   911  					{types.NewOkResult(1)},
   912  				},
   913  			},
   914  			{
   915  				User:  "root",
   916  				Host:  "localhost",
   917  				Query: "DELETE FROM dolt_branch_control WHERE user = 'testuser' AND host = 'localhost';",
   918  				Expected: []sql.Row{
   919  					{types.NewOkResult(1)},
   920  				},
   921  			},
   922  			{
   923  				User:     "testuser",
   924  				Host:     "localhost",
   925  				Query:    "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
   926  				Expected: []sql.Row{},
   927  			},
   928  			{
   929  				User:        "testuser",
   930  				Host:        "localhost",
   931  				Query:       "INSERT INTO test VALUES (5);",
   932  				ExpectedErr: branch_control.ErrIncorrectPermissions,
   933  			},
   934  			{
   935  				User:  "root",
   936  				Host:  "localhost",
   937  				Query: "DELETE FROM dolt_branch_control;",
   938  				Expected: []sql.Row{
   939  					{types.NewOkResult(1)},
   940  				},
   941  			},
   942  			{
   943  				User:     "root",
   944  				Host:     "localhost",
   945  				Query:    "SELECT * FROM dolt_branch_control;",
   946  				Expected: []sql.Row{},
   947  			},
   948  			{
   949  				User:  "root",
   950  				Host:  "localhost",
   951  				Query: "INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', '%', 'admin');",
   952  				Expected: []sql.Row{
   953  					{types.NewOkResult(1)},
   954  				},
   955  			},
   956  			{
   957  				User:  "root",
   958  				Host:  "localhost",
   959  				Query: "SELECT * FROM dolt_branch_control;",
   960  				Expected: []sql.Row{
   961  					{"%", "%", "root", "%", "admin"},
   962  				},
   963  			},
   964  		},
   965  	},
   966  	{
   967  		Name: "Subset entries count as duplicates",
   968  		SetUpScript: []string{
   969  			"DELETE FROM dolt_branch_control WHERE user = '%';",
   970  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
   971  			"CREATE USER testuser@localhost;",
   972  			"GRANT ALL ON *.* TO testuser@localhost;",
   973  			"INSERT INTO dolt_branch_control VALUES ('%', 'prefix', 'testuser', 'localhost', 'admin');",
   974  			"INSERT INTO dolt_branch_control VALUES ('%', 'prefix1%', 'testuser', 'localhost', 'admin');",
   975  			"INSERT INTO dolt_branch_control VALUES ('%', 'prefix2_', 'testuser', 'localhost', 'admin');",
   976  			"INSERT INTO dolt_branch_control VALUES ('%', 'prefix3_', 'testuser', 'localhost', 'admin');",
   977  		},
   978  		Assertions: []BranchControlTestAssertion{
   979  			{ // The pre-existing "prefix1%" entry will cover ALL possible matches of "prefix1sub%", so we treat it as a duplicate
   980  				User:        "testuser",
   981  				Host:        "localhost",
   982  				Query:       "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1sub%', 'testuser', 'localhost', 'admin');",
   983  				ExpectedErr: sql.ErrPrimaryKeyViolation,
   984  			},
   985  			{ // The ending "%" fully covers "_", so we also treat it as a duplicate
   986  				User:        "testuser",
   987  				Host:        "localhost",
   988  				Query:       "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1_', 'testuser', 'localhost', 'admin');",
   989  				ExpectedErr: sql.ErrPrimaryKeyViolation,
   990  			},
   991  			{ // This is the reverse of the above case, so this is NOT a duplicate (although the original is now a subset)
   992  				User:  "root",
   993  				Host:  "localhost",
   994  				Query: "INSERT INTO dolt_branch_control VALUES ('%', 'prefix2%', 'testuser', 'localhost', 'admin');",
   995  				Expected: []sql.Row{
   996  					{types.NewOkResult(1)},
   997  				},
   998  			},
   999  			{
  1000  				User:  "testuser",
  1001  				Host:  "localhost",
  1002  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1003  				Expected: []sql.Row{
  1004  					{"%", "prefix", "testuser", "localhost", "admin"},
  1005  					{"%", "prefix1%", "testuser", "localhost", "admin"},
  1006  					{"%", "prefix2_", "testuser", "localhost", "admin"},
  1007  					{"%", "prefix2%", "testuser", "localhost", "admin"},
  1008  					{"%", "prefix3_", "testuser", "localhost", "admin"},
  1009  				},
  1010  			},
  1011  			{ // Sanity checks to ensure that straight-up duplicates are also caught
  1012  				User:        "testuser",
  1013  				Host:        "localhost",
  1014  				Query:       "INSERT INTO dolt_branch_control VALUES ('%', 'prefix', 'testuser', 'localhost', 'admin');",
  1015  				ExpectedErr: sql.ErrPrimaryKeyViolation,
  1016  			},
  1017  			{
  1018  				User:        "testuser",
  1019  				Host:        "localhost",
  1020  				Query:       "INSERT INTO dolt_branch_control VALUES ('%', 'prefix1%', 'testuser', 'localhost', 'admin');",
  1021  				ExpectedErr: sql.ErrPrimaryKeyViolation,
  1022  			},
  1023  			{
  1024  				User:        "testuser",
  1025  				Host:        "localhost",
  1026  				Query:       "INSERT INTO dolt_branch_control VALUES ('%', 'prefix3_', 'testuser', 'localhost', 'admin');",
  1027  				ExpectedErr: sql.ErrPrimaryKeyViolation,
  1028  			},
  1029  			{ // Verify that creating branches also skips adding an entry if it would be a subset
  1030  				User:  "root",
  1031  				Host:  "localhost",
  1032  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'root';",
  1033  				Expected: []sql.Row{
  1034  					{"%", "%", "root", "localhost", "admin"},
  1035  				},
  1036  			},
  1037  			{
  1038  				User:     "root",
  1039  				Host:     "localhost",
  1040  				Query:    "CALL DOLT_BRANCH('new_root_branch');",
  1041  				Expected: []sql.Row{{0}},
  1042  			},
  1043  			{
  1044  				User:  "root",
  1045  				Host:  "localhost",
  1046  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'root';",
  1047  				Expected: []sql.Row{
  1048  					{"%", "%", "root", "localhost", "admin"},
  1049  				},
  1050  			},
  1051  		},
  1052  	},
  1053  	{
  1054  		Name: "Creating branch creates new entry",
  1055  		SetUpScript: []string{
  1056  			"DELETE FROM dolt_branch_control WHERE user = '%';",
  1057  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
  1058  			"CREATE USER testuser@localhost;",
  1059  			"GRANT ALL ON *.* TO testuser@localhost;",
  1060  		},
  1061  		Assertions: []BranchControlTestAssertion{
  1062  			{
  1063  				User:     "testuser",
  1064  				Host:     "localhost",
  1065  				Query:    "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1066  				Expected: []sql.Row{},
  1067  			},
  1068  			{
  1069  				User:     "testuser",
  1070  				Host:     "localhost",
  1071  				Query:    "CALL DOLT_BRANCH('otherbranch');",
  1072  				Expected: []sql.Row{{0}},
  1073  			},
  1074  			{
  1075  				User:  "testuser",
  1076  				Host:  "localhost",
  1077  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1078  				Expected: []sql.Row{
  1079  					{"mydb", "otherbranch", "testuser", "localhost", "admin"},
  1080  				},
  1081  			},
  1082  		},
  1083  	},
  1084  	{
  1085  		Name: "Renaming branch creates new entry",
  1086  		SetUpScript: []string{
  1087  			"DELETE FROM dolt_branch_control WHERE user = '%';",
  1088  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
  1089  			"CREATE USER testuser@localhost;",
  1090  			"GRANT ALL ON *.* TO testuser@localhost;",
  1091  			"CALL DOLT_BRANCH('otherbranch');",
  1092  			"INSERT INTO dolt_branch_control VALUES ('%', 'otherbranch', 'testuser', 'localhost', 'write');",
  1093  		},
  1094  		Assertions: []BranchControlTestAssertion{
  1095  			{
  1096  				User:  "testuser",
  1097  				Host:  "localhost",
  1098  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1099  				Expected: []sql.Row{
  1100  					{"%", "otherbranch", "testuser", "localhost", "write"},
  1101  				},
  1102  			},
  1103  			{
  1104  				User:        "testuser",
  1105  				Host:        "localhost",
  1106  				Query:       "CALL DOLT_BRANCH('-f', '-m', 'otherbranch', 'newbranch');",
  1107  				ExpectedErr: branch_control.ErrCannotDeleteBranch,
  1108  			},
  1109  			{
  1110  				User:     "testuser",
  1111  				Host:     "localhost",
  1112  				Query:    "CALL DOLT_BRANCH('-m', 'otherbranch', 'newbranch');",
  1113  				Expected: []sql.Row{{0}},
  1114  			},
  1115  			{
  1116  				User:  "testuser",
  1117  				Host:  "localhost",
  1118  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1119  				Expected: []sql.Row{
  1120  					{"%", "otherbranch", "testuser", "localhost", "write"},  // Original entry remains
  1121  					{"mydb", "newbranch", "testuser", "localhost", "admin"}, // New entry is scoped specifically to db
  1122  				},
  1123  			},
  1124  		},
  1125  	},
  1126  	{
  1127  		Name: "Copying branch creates new entry",
  1128  		SetUpScript: []string{
  1129  			"DELETE FROM dolt_branch_control WHERE user = '%';",
  1130  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
  1131  			"CREATE USER testuser@localhost;",
  1132  			"GRANT ALL ON *.* TO testuser@localhost;",
  1133  			"CALL DOLT_BRANCH('otherbranch');",
  1134  		},
  1135  		Assertions: []BranchControlTestAssertion{
  1136  			{
  1137  				User:     "testuser",
  1138  				Host:     "localhost",
  1139  				Query:    "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1140  				Expected: []sql.Row{},
  1141  			},
  1142  			{
  1143  				User:        "testuser",
  1144  				Host:        "localhost",
  1145  				Query:       "CALL DOLT_BRANCH('-f', '-c', 'otherbranch', 'newbranch');",
  1146  				ExpectedErr: branch_control.ErrCannotDeleteBranch,
  1147  			},
  1148  			{
  1149  				User:     "testuser",
  1150  				Host:     "localhost",
  1151  				Query:    "CALL DOLT_BRANCH('-c', 'otherbranch', 'newbranch');",
  1152  				Expected: []sql.Row{{0}},
  1153  			},
  1154  			{
  1155  				User:  "testuser",
  1156  				Host:  "localhost",
  1157  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1158  				Expected: []sql.Row{
  1159  					{"mydb", "newbranch", "testuser", "localhost", "admin"},
  1160  				},
  1161  			},
  1162  		},
  1163  	},
  1164  	{
  1165  		Name: "Proper database scoping",
  1166  		SetUpScript: []string{
  1167  			"DELETE FROM dolt_branch_control WHERE user = '%';",
  1168  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin')," +
  1169  				"('dba', 'main', 'testuser', 'localhost', 'write'), ('dbb', 'other', 'testuser', 'localhost', 'write');",
  1170  			"CREATE DATABASE dba;", // Implicitly creates "main" branch
  1171  			"CREATE DATABASE dbb;", // Implicitly creates "main" branch
  1172  			"CREATE USER testuser@localhost;",
  1173  			"GRANT ALL ON *.* TO testuser@localhost;",
  1174  			"USE dba;",
  1175  			"CALL DOLT_BRANCH('other');",
  1176  			"USE dbb;",
  1177  			"CALL DOLT_BRANCH('other');",
  1178  		},
  1179  		Assertions: []BranchControlTestAssertion{
  1180  			{
  1181  				User:     "testuser",
  1182  				Host:     "localhost",
  1183  				Query:    "USE dba;",
  1184  				Expected: []sql.Row{},
  1185  			},
  1186  			{ // On "dba"."main", which we have permissions for
  1187  				User:  "testuser",
  1188  				Host:  "localhost",
  1189  				Query: "CREATE TABLE test (pk BIGINT PRIMARY KEY);",
  1190  				Expected: []sql.Row{
  1191  					{types.NewOkResult(0)},
  1192  				},
  1193  			},
  1194  			{
  1195  				User:  "testuser",
  1196  				Host:  "localhost",
  1197  				Query: "DROP TABLE test;",
  1198  				Expected: []sql.Row{
  1199  					{types.NewOkResult(0)},
  1200  				},
  1201  			},
  1202  			{
  1203  				User:     "testuser",
  1204  				Host:     "localhost",
  1205  				Query:    "CALL DOLT_CHECKOUT('other');",
  1206  				Expected: []sql.Row{{0, "Switched to branch 'other'"}},
  1207  			},
  1208  			{ // On "dba"."other", which we do not have permissions for
  1209  				User:        "testuser",
  1210  				Host:        "localhost",
  1211  				Query:       "CREATE TABLE test (pk BIGINT PRIMARY KEY);",
  1212  				ExpectedErr: branch_control.ErrIncorrectPermissions,
  1213  			},
  1214  			{
  1215  				User:     "testuser",
  1216  				Host:     "localhost",
  1217  				Query:    "USE dbb;",
  1218  				Expected: []sql.Row{},
  1219  			},
  1220  			{ // On "dbb"."main", which we do not have permissions for
  1221  				User:        "testuser",
  1222  				Host:        "localhost",
  1223  				Query:       "CREATE TABLE test (pk BIGINT PRIMARY KEY);",
  1224  				ExpectedErr: branch_control.ErrIncorrectPermissions,
  1225  			},
  1226  			{
  1227  				User:     "testuser",
  1228  				Host:     "localhost",
  1229  				Query:    "CALL DOLT_CHECKOUT('other');",
  1230  				Expected: []sql.Row{{0, "Switched to branch 'other'"}},
  1231  			},
  1232  			{ // On "dbb"."other", which we do not have permissions for
  1233  				User:  "testuser",
  1234  				Host:  "localhost",
  1235  				Query: "CREATE TABLE test (pk BIGINT PRIMARY KEY);",
  1236  				Expected: []sql.Row{
  1237  					{types.NewOkResult(0)},
  1238  				},
  1239  			},
  1240  		},
  1241  	},
  1242  	{
  1243  		Name: "Admin privileges do not give implicit branch permissions",
  1244  		SetUpScript: []string{
  1245  			"DELETE FROM dolt_branch_control WHERE user = '%';",
  1246  			// Even though root already has all privileges, this makes the test logic a bit more explicit
  1247  			"CREATE USER testuser@localhost;",
  1248  			"GRANT ALL ON *.* TO testuser@localhost WITH GRANT OPTION;",
  1249  		},
  1250  		Assertions: []BranchControlTestAssertion{
  1251  			{
  1252  				User:        "testuser",
  1253  				Host:        "localhost",
  1254  				Query:       "CREATE TABLE test (pk BIGINT PRIMARY KEY);",
  1255  				ExpectedErr: branch_control.ErrIncorrectPermissions,
  1256  			},
  1257  			{
  1258  				User:        "testuser",
  1259  				Host:        "localhost",
  1260  				Query:       "CALL DOLT_BRANCH('-m', 'main', 'newbranch');",
  1261  				ExpectedErr: branch_control.ErrCannotDeleteBranch,
  1262  			},
  1263  			{ // Anyone can create a branch as long as it's not blocked by dolt_branch_namespace_control
  1264  				User:     "testuser",
  1265  				Host:     "localhost",
  1266  				Query:    "CALL DOLT_BRANCH('newbranch');",
  1267  				Expected: []sql.Row{{0}},
  1268  			},
  1269  			{
  1270  				User:  "testuser",
  1271  				Host:  "localhost",
  1272  				Query: "SELECT * FROM dolt_branch_control WHERE user = 'testuser';",
  1273  				Expected: []sql.Row{
  1274  					{"mydb", "newbranch", "testuser", "localhost", "admin"},
  1275  				},
  1276  			},
  1277  		},
  1278  	},
  1279  	{
  1280  		Name: "Database-level admin privileges allow scoped table modifications",
  1281  		SetUpScript: []string{
  1282  			"DELETE FROM dolt_branch_control WHERE user = '%';",
  1283  			"INSERT INTO dolt_branch_control VALUES ('%', '%', 'root', 'localhost', 'admin');",
  1284  			"CREATE DATABASE dba;",
  1285  			"CREATE DATABASE dbb;",
  1286  			"CREATE USER a@localhost;",
  1287  			"GRANT ALL ON dba.* TO a@localhost WITH GRANT OPTION;",
  1288  			"CREATE USER b@localhost;",
  1289  			"GRANT ALL ON dbb.* TO b@localhost WITH GRANT OPTION;",
  1290  			// Currently, dolt system tables are scoped to the current database, so this is a workaround for that
  1291  			"GRANT ALL ON mydb.* TO a@localhost;",
  1292  			"GRANT ALL ON mydb.* TO b@localhost;",
  1293  		},
  1294  		Assertions: []BranchControlTestAssertion{
  1295  			{
  1296  				User:  "a",
  1297  				Host:  "localhost",
  1298  				Query: "INSERT INTO dolt_branch_control VALUES ('dba', 'dummy1', '%', '%', 'write');",
  1299  				Expected: []sql.Row{
  1300  					{types.NewOkResult(1)},
  1301  				},
  1302  			},
  1303  			{
  1304  				User:        "a",
  1305  				Host:        "localhost",
  1306  				Query:       "INSERT INTO dolt_branch_control VALUES ('db_', 'dummy2', '%', '%', 'write');",
  1307  				ExpectedErr: branch_control.ErrInsertingAccessRow,
  1308  			},
  1309  			{
  1310  				User:        "a",
  1311  				Host:        "localhost",
  1312  				Query:       "INSERT INTO dolt_branch_control VALUES ('dbb', 'dummy3', '%', '%', 'write');",
  1313  				ExpectedErr: branch_control.ErrInsertingAccessRow,
  1314  			},
  1315  			{
  1316  				User:        "b",
  1317  				Host:        "localhost",
  1318  				Query:       "INSERT INTO dolt_branch_control VALUES ('dba', 'dummy4', '%', '%', 'write');",
  1319  				ExpectedErr: branch_control.ErrInsertingAccessRow,
  1320  			},
  1321  			{
  1322  				User:        "b",
  1323  				Host:        "localhost",
  1324  				Query:       "INSERT INTO dolt_branch_control VALUES ('db_', 'dummy5', '%', '%', 'write');",
  1325  				ExpectedErr: branch_control.ErrInsertingAccessRow,
  1326  			},
  1327  			{
  1328  				User:  "b",
  1329  				Host:  "localhost",
  1330  				Query: "INSERT INTO dolt_branch_control VALUES ('dbb', 'dummy6', '%', '%', 'write');",
  1331  				Expected: []sql.Row{
  1332  					{types.NewOkResult(1)},
  1333  				},
  1334  			},
  1335  			{
  1336  				User:  "root",
  1337  				Host:  "localhost",
  1338  				Query: "GRANT SUPER ON *.* TO a@localhost WITH GRANT OPTION;",
  1339  				Expected: []sql.Row{
  1340  					{types.NewOkResult(0)},
  1341  				},
  1342  			},
  1343  			{
  1344  				User:  "a",
  1345  				Host:  "localhost",
  1346  				Query: "INSERT INTO dolt_branch_control VALUES ('db_', 'dummy7', '%', '%', 'write');",
  1347  				Expected: []sql.Row{
  1348  					{types.NewOkResult(1)},
  1349  				},
  1350  			},
  1351  			{
  1352  				User:  "root",
  1353  				Host:  "localhost",
  1354  				Query: "SELECT * FROM dolt_branch_control;",
  1355  				Expected: []sql.Row{
  1356  					{"%", "%", "root", "localhost", "admin"},
  1357  					{"dba", "dummy1", "%", "%", "write"},
  1358  					{"dbb", "dummy6", "%", "%", "write"},
  1359  					{"db_", "dummy7", "%", "%", "write"},
  1360  				},
  1361  			},
  1362  		},
  1363  	},
  1364  }
  1365  
  1366  func TestBranchControl(t *testing.T) {
  1367  	for _, test := range BranchControlTests {
  1368  		harness := newDoltHarness(t)
  1369  		defer harness.Close()
  1370  		t.Run(test.Name, func(t *testing.T) {
  1371  			engine, err := harness.NewEngine(t)
  1372  			require.NoError(t, err)
  1373  			defer engine.Close()
  1374  
  1375  			ctx := enginetest.NewContext(harness)
  1376  			ctx.NewCtxWithClient(sql.Client{
  1377  				User:    "root",
  1378  				Address: "localhost",
  1379  			})
  1380  			engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount()
  1381  			engine.EngineAnalyzer().Catalog.MySQLDb.SetPersister(&mysql_db.NoopPersister{})
  1382  
  1383  			for _, statement := range test.SetUpScript {
  1384  				enginetest.RunQueryWithContext(t, engine, harness, ctx, statement)
  1385  			}
  1386  
  1387  			for _, assertion := range test.Assertions {
  1388  				user := assertion.User
  1389  				host := assertion.Host
  1390  				if user == "" {
  1391  					user = "root"
  1392  				}
  1393  				if host == "" {
  1394  					host = "localhost"
  1395  				}
  1396  				ctx = ctx.NewCtxWithClient(sql.Client{
  1397  					User:    user,
  1398  					Address: host,
  1399  				})
  1400  
  1401  				if assertion.ExpectedErr != nil {
  1402  					t.Run(assertion.Query, func(t *testing.T) {
  1403  						enginetest.AssertErrWithCtx(t, engine, harness, ctx, assertion.Query, assertion.ExpectedErr)
  1404  					})
  1405  				} else if assertion.ExpectedErrStr != "" {
  1406  					t.Run(assertion.Query, func(t *testing.T) {
  1407  						enginetest.AssertErrWithCtx(t, engine, harness, ctx, assertion.Query, nil, assertion.ExpectedErrStr)
  1408  					})
  1409  				} else {
  1410  					t.Run(assertion.Query, func(t *testing.T) {
  1411  						enginetest.TestQueryWithContext(t, ctx, engine, harness, assertion.Query, assertion.Expected, nil, nil)
  1412  					})
  1413  				}
  1414  			}
  1415  		})
  1416  	}
  1417  }
  1418  
  1419  func TestBranchControlBlocks(t *testing.T) {
  1420  	for _, test := range BranchControlBlockTests {
  1421  		t.Run(test.Name, func(t *testing.T) {
  1422  			if test.SkipMessage != "" {
  1423  				t.Skip(test.SkipMessage)
  1424  			}
  1425  
  1426  			harness := newDoltHarness(t)
  1427  			defer harness.Close()
  1428  
  1429  			engine, err := harness.NewEngine(t)
  1430  			require.NoError(t, err)
  1431  			defer engine.Close()
  1432  
  1433  			rootCtx := enginetest.NewContext(harness)
  1434  			rootCtx.NewCtxWithClient(sql.Client{
  1435  				User:    "root",
  1436  				Address: "localhost",
  1437  			})
  1438  			engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount()
  1439  			engine.EngineAnalyzer().Catalog.MySQLDb.SetPersister(&mysql_db.NoopPersister{})
  1440  
  1441  			for _, statement := range append(TestUserSetUpScripts, test.SetUpScript...) {
  1442  				enginetest.RunQueryWithContext(t, engine, harness, rootCtx, statement)
  1443  			}
  1444  
  1445  			userCtx := enginetest.NewContextWithClient(harness, sql.Client{
  1446  				User:    "testuser",
  1447  				Address: "localhost",
  1448  			})
  1449  			enginetest.AssertErrWithCtx(t, engine, harness, userCtx, test.Query, test.ExpectedErr)
  1450  
  1451  			addUserQuery := "INSERT INTO dolt_branch_control VALUES ('%', 'main', 'testuser', 'localhost', 'write'), ('%', 'other', 'testuser', 'localhost', 'write');"
  1452  			addUserQueryResults := []sql.Row{{types.NewOkResult(2)}}
  1453  			enginetest.TestQueryWithContext(t, rootCtx, engine, harness, addUserQuery, addUserQueryResults, nil, nil)
  1454  
  1455  			_, iter, err := engine.Query(userCtx, test.Query)
  1456  			if err == nil {
  1457  				_, err = sql.RowIterToRows(userCtx, iter)
  1458  			}
  1459  			assert.NoError(t, err)
  1460  		})
  1461  	}
  1462  
  1463  	// These tests are run with permission on main but not other
  1464  	for _, test := range BranchControlOtherDbBlockTests {
  1465  		t.Run("OtherDB_"+test.Name, func(t *testing.T) {
  1466  			if test.SkipMessage != "" {
  1467  				t.Skip(test.SkipMessage)
  1468  			}
  1469  
  1470  			harness := newDoltHarness(t)
  1471  			defer harness.Close()
  1472  
  1473  			engine, err := harness.NewEngine(t)
  1474  			require.NoError(t, err)
  1475  			defer engine.Close()
  1476  
  1477  			rootCtx := enginetest.NewContext(harness)
  1478  			rootCtx.NewCtxWithClient(sql.Client{
  1479  				User:    "root",
  1480  				Address: "localhost",
  1481  			})
  1482  			engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount()
  1483  			engine.EngineAnalyzer().Catalog.MySQLDb.SetPersister(&mysql_db.NoopPersister{})
  1484  
  1485  			for _, statement := range append(TestUserSetUpScripts, test.SetUpScript...) {
  1486  				enginetest.RunQueryWithContext(t, engine, harness, rootCtx, statement)
  1487  			}
  1488  
  1489  			addUserQuery := "INSERT INTO dolt_branch_control VALUES ('%', 'main', 'testuser', 'localhost', 'write');"
  1490  			addUserQueryResults := []sql.Row{{types.NewOkResult(1)}}
  1491  			enginetest.TestQueryWithContext(t, rootCtx, engine, harness, addUserQuery, addUserQueryResults, nil, nil)
  1492  
  1493  			userCtx := enginetest.NewContextWithClient(harness, sql.Client{
  1494  				User:    "testuser",
  1495  				Address: "localhost",
  1496  			})
  1497  			enginetest.AssertErrWithCtx(t, engine, harness, userCtx, test.Query, test.ExpectedErr)
  1498  
  1499  			addUserQuery = "INSERT INTO dolt_branch_control VALUES ('%', 'other', 'testuser', 'localhost', 'write');"
  1500  			addUserQueryResults = []sql.Row{{types.NewOkResult(1)}}
  1501  			enginetest.TestQueryWithContext(t, rootCtx, engine, harness, addUserQuery, addUserQueryResults, nil, nil)
  1502  
  1503  			_, iter, err := engine.Query(userCtx, test.Query)
  1504  			if err == nil {
  1505  				_, err = sql.RowIterToRows(userCtx, iter)
  1506  			}
  1507  			assert.NoError(t, err)
  1508  		})
  1509  	}
  1510  }