vitess.io/vitess@v0.16.2/go/vt/vtgate/executor_vschema_ddl_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vtgate 18 19 import ( 20 "reflect" 21 "sort" 22 "testing" 23 "time" 24 25 "vitess.io/vitess/go/test/utils" 26 27 "vitess.io/vitess/go/vt/callerid" 28 querypb "vitess.io/vitess/go/vt/proto/query" 29 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 30 31 "context" 32 33 "vitess.io/vitess/go/sqltypes" 34 "vitess.io/vitess/go/vt/vtgate/vschemaacl" 35 36 "github.com/stretchr/testify/assert" 37 "github.com/stretchr/testify/require" 38 39 vschemapb "vitess.io/vitess/go/vt/proto/vschema" 40 vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" 41 ) 42 43 func waitForVindex(t *testing.T, ks, name string, watch chan *vschemapb.SrvVSchema, executor *Executor) (*vschemapb.SrvVSchema, *vschemapb.Vindex) { 44 t.Helper() 45 46 // Wait up to 10ms until the watch gets notified of the update 47 ok := false 48 for i := 0; i < 10; i++ { 49 select { 50 case vschema := <-watch: 51 _, ok = vschema.Keyspaces[ks].Vindexes[name] 52 if !ok { 53 t.Errorf("updated vschema did not contain %s", name) 54 } 55 default: 56 time.Sleep(time.Millisecond) 57 } 58 } 59 if !ok { 60 t.Errorf("vschema was not updated as expected") 61 } 62 63 // Wait up to 100ms until the vindex manager gets notified of the update 64 for i := 0; i < 10; i++ { 65 vschema := executor.vm.GetCurrentSrvVschema() 66 vindex, ok := vschema.Keyspaces[ks].Vindexes[name] 67 if ok { 68 return vschema, vindex 69 } 70 time.Sleep(10 * time.Millisecond) 71 } 72 73 t.Fatalf("updated vschema did not contain %s", name) 74 return nil, nil 75 } 76 77 func waitForVschemaTables(t *testing.T, ks string, tables []string, executor *Executor) *vschemapb.SrvVSchema { 78 t.Helper() 79 80 // Wait up to 100ms until the vindex manager gets notified of the update 81 for i := 0; i < 10; i++ { 82 vschema := executor.vm.GetCurrentSrvVschema() 83 gotTables := []string{} 84 for t := range vschema.Keyspaces[ks].Tables { 85 gotTables = append(gotTables, t) 86 } 87 sort.Strings(tables) 88 sort.Strings(gotTables) 89 if reflect.DeepEqual(tables, gotTables) { 90 return vschema 91 } 92 time.Sleep(10 * time.Millisecond) 93 } 94 95 t.Fatalf("updated vschema did not contain tables %v", tables) 96 return nil 97 } 98 99 // nolint 100 func waitForColVindexes(t *testing.T, ks, table string, names []string, executor *Executor) *vschemapb.SrvVSchema { 101 t.Helper() 102 103 // Wait up to 10ms until the vindex manager gets notified of the update 104 for i := 0; i < 10; i++ { 105 106 vschema := executor.vm.GetCurrentSrvVschema() 107 table, ok := vschema.Keyspaces[ks].Tables[table] 108 109 // The table is removed from the vschema when there are no 110 // vindexes defined 111 if !ok == (len(names) == 0) { 112 return vschema 113 } else if ok && (len(names) == len(table.ColumnVindexes)) { 114 match := true 115 for i, name := range names { 116 if name != table.ColumnVindexes[i].Name { 117 match = false 118 break 119 } 120 } 121 if match { 122 return vschema 123 } 124 } 125 126 time.Sleep(time.Millisecond) 127 128 } 129 130 t.Fatalf("updated vschema did not contain vindexes %v on table %s", names, table) 131 return nil 132 } 133 134 func TestPlanExecutorAlterVSchemaKeyspace(t *testing.T) { 135 vschemaacl.AuthorizedDDLUsers = "%" 136 defer func() { 137 vschemaacl.AuthorizedDDLUsers = "" 138 }() 139 executor, _, _, _ := createExecutorEnv() 140 session := NewSafeSession(&vtgatepb.Session{TargetString: "@primary", Autocommit: true}) 141 142 vschemaUpdates := make(chan *vschemapb.SrvVSchema, 2) 143 executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) bool { 144 vschemaUpdates <- vschema 145 return true 146 }) 147 148 vschema := <-vschemaUpdates 149 _, ok := vschema.Keyspaces["TestExecutor"].Vindexes["test_vindex"] 150 if ok { 151 t.Fatalf("test_vindex should not exist in original vschema") 152 } 153 154 stmt := "alter vschema create vindex TestExecutor.test_vindex using hash" 155 _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 156 require.NoError(t, err) 157 158 _, vindex := waitForVindex(t, "TestExecutor", "test_vindex", vschemaUpdates, executor) 159 assert.Equal(t, vindex.Type, "hash") 160 } 161 162 func TestPlanExecutorCreateVindexDDL(t *testing.T) { 163 vschemaacl.AuthorizedDDLUsers = "%" 164 defer func() { 165 vschemaacl.AuthorizedDDLUsers = "" 166 }() 167 executor, _, _, _ := createExecutorEnv() 168 ks := "TestExecutor" 169 170 vschemaUpdates := make(chan *vschemapb.SrvVSchema, 4) 171 executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) bool { 172 vschemaUpdates <- vschema 173 return true 174 }) 175 176 vschema := <-vschemaUpdates 177 _, ok := vschema.Keyspaces[ks].Vindexes["test_vindex"] 178 if ok { 179 t.Fatalf("test_vindex should not exist in original vschema") 180 } 181 182 session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) 183 stmt := "alter vschema create vindex test_vindex using hash" 184 _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 185 require.NoError(t, err) 186 187 _, vindex := waitForVindex(t, ks, "test_vindex", vschemaUpdates, executor) 188 if vindex == nil || vindex.Type != "hash" { 189 t.Errorf("updated vschema did not contain test_vindex") 190 } 191 192 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 193 wantErr := "vindex test_vindex already exists in keyspace TestExecutor" 194 if err == nil || err.Error() != wantErr { 195 t.Errorf("create duplicate vindex: %v, want %s", err, wantErr) 196 } 197 select { 198 case <-vschemaUpdates: 199 t.Error("vschema should not be updated on error") 200 default: 201 } 202 } 203 204 func TestPlanExecutorDropVindexDDL(t *testing.T) { 205 vschemaacl.AuthorizedDDLUsers = "%" 206 defer func() { 207 vschemaacl.AuthorizedDDLUsers = "" 208 }() 209 executor, _, _, _ := createExecutorEnv() 210 ks := "TestExecutor" 211 212 vschemaUpdates := make(chan *vschemapb.SrvVSchema, 4) 213 executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) bool { 214 vschemaUpdates <- vschema 215 return true 216 }) 217 218 vschema := <-vschemaUpdates 219 _, ok := vschema.Keyspaces[ks].Vindexes["test_vindex"] 220 if ok { 221 t.Fatalf("test_vindex should not exist in original vschema") 222 } 223 224 session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) 225 stmt := "alter vschema drop vindex test_vindex" 226 _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 227 wantErr := "vindex test_vindex does not exists in keyspace TestExecutor" 228 if err == nil || err.Error() != wantErr { 229 t.Errorf("want error %v got %v", wantErr, err) 230 } 231 232 stmt = "alter vschema drop vindex TestExecutor.test_vindex" 233 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 234 wantErr = "vindex test_vindex does not exists in keyspace TestExecutor" 235 if err == nil || err.Error() != wantErr { 236 t.Errorf("want error %v got %v", wantErr, err) 237 } 238 239 // add one vindex that has never been used by the tables 240 stmt = "alter vschema create vindex test_vindex using hash" 241 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 242 require.NoError(t, err) 243 244 _, vindex := waitForVindex(t, ks, "test_vindex", vschemaUpdates, executor) 245 if vindex == nil || vindex.Type != "hash" { 246 t.Errorf("updated vschema did not contain test_vindex") 247 } 248 249 // drop an existing vindex that has never been used by the tables 250 stmt = "alter vschema drop vindex TestExecutor.test_vindex" 251 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 252 require.NoError(t, err) 253 vschema = <-vschemaUpdates 254 _, ok = vschema.Keyspaces[ks].Vindexes["test_vindex"] 255 if ok { 256 t.Fatalf("test_vindex should not exist after droping it") 257 } 258 259 // drop an existing vindex that is used by at least one table 260 stmt = "alter vschema drop vindex TestExecutor.keyspace_id" 261 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 262 wantErr = "can not drop vindex cause keyspace_id still defined on table ksid_table" 263 if err == nil || err.Error() != wantErr { 264 t.Errorf("drop vindex still defined: %v, want %s", err, wantErr) 265 } 266 select { 267 case <-vschemaUpdates: 268 t.Error("vschema should not be updated on error") 269 default: 270 } 271 } 272 273 func TestPlanExecutorAddDropVschemaTableDDL(t *testing.T) { 274 vschemaacl.AuthorizedDDLUsers = "%" 275 defer func() { 276 vschemaacl.AuthorizedDDLUsers = "" 277 }() 278 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 279 ks := KsTestUnsharded 280 281 vschemaUpdates := make(chan *vschemapb.SrvVSchema, 4) 282 executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) bool { 283 vschemaUpdates <- vschema 284 return true 285 }) 286 287 vschema := <-vschemaUpdates 288 _, ok := vschema.Keyspaces[ks].Tables["test_table"] 289 if ok { 290 t.Fatalf("test_table should not exist in original vschema") 291 } 292 293 vschemaTables := []string{} 294 for t := range vschema.Keyspaces[ks].Tables { 295 vschemaTables = append(vschemaTables, t) 296 } 297 298 session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) 299 stmt := "alter vschema add table test_table" 300 _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 301 require.NoError(t, err) 302 _ = waitForVschemaTables(t, ks, append([]string{"test_table"}, vschemaTables...), executor) 303 304 stmt = "alter vschema add table test_table2" 305 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 306 require.NoError(t, err) 307 _ = waitForVschemaTables(t, ks, append([]string{"test_table", "test_table2"}, vschemaTables...), executor) 308 309 // Should fail adding a table on a sharded keyspace 310 session = NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}) 311 stmt = "alter vschema add table test_table" 312 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 313 wantErr := "add vschema table: unsupported on sharded keyspace TestExecutor" 314 if err == nil || err.Error() != wantErr { 315 t.Errorf("want error %v got %v", wantErr, err) 316 } 317 318 // No queries should have gone to any tablets 319 wantCount := []int64{0, 0, 0} 320 gotCount := []int64{ 321 sbc1.ExecCount.Get(), 322 sbc2.ExecCount.Get(), 323 sbclookup.ExecCount.Get(), 324 } 325 if !reflect.DeepEqual(gotCount, wantCount) { 326 t.Errorf("Exec %s: %v, want %v", stmt, gotCount, wantCount) 327 } 328 } 329 330 func TestExecutorAddSequenceDDL(t *testing.T) { 331 vschemaacl.AuthorizedDDLUsers = "%" 332 defer func() { 333 vschemaacl.AuthorizedDDLUsers = "" 334 }() 335 executor, _, _, _ := createExecutorEnv() 336 ks := KsTestUnsharded 337 338 vschema := executor.vm.GetCurrentSrvVschema() 339 340 var vschemaTables []string 341 for t := range vschema.Keyspaces[ks].Tables { 342 vschemaTables = append(vschemaTables, t) 343 } 344 345 session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) 346 stmt := "alter vschema add sequence test_seq" 347 _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 348 require.NoError(t, err) 349 _ = waitForVschemaTables(t, ks, append(vschemaTables, []string{"test_seq"}...), executor) 350 vschema = executor.vm.GetCurrentSrvVschema() 351 table := vschema.Keyspaces[ks].Tables["test_seq"] 352 wantType := "sequence" 353 if table.Type != wantType { 354 t.Errorf("want table type sequence got %v", table) 355 } 356 357 // Should fail adding a table on a sharded keyspace 358 ksSharded := "TestExecutor" 359 session = NewSafeSession(&vtgatepb.Session{TargetString: ksSharded}) 360 361 stmt = "alter vschema add sequence sequence_table" 362 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 363 364 wantErr := "add sequence table: unsupported on sharded keyspace TestExecutor" 365 if err == nil || err.Error() != wantErr { 366 t.Errorf("want error %v got %v", wantErr, err) 367 } 368 369 // Should be able to add autoincrement to table in sharded keyspace 370 stmt = "alter vschema on test_table add vindex hash_index (id)" 371 if _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil); err != nil { 372 t.Error(err) 373 } 374 time.Sleep(10 * time.Millisecond) 375 376 stmt = "alter vschema on test_table add auto_increment id using `db-name`.`test_seq`" 377 if _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil); err != nil { 378 t.Error(err) 379 } 380 time.Sleep(10 * time.Millisecond) 381 382 wantAutoInc := &vschemapb.AutoIncrement{Column: "id", Sequence: "`db-name`.test_seq"} 383 gotAutoInc := executor.vm.GetCurrentSrvVschema().Keyspaces[ksSharded].Tables["test_table"].AutoIncrement 384 385 if !reflect.DeepEqual(wantAutoInc, gotAutoInc) { 386 t.Errorf("want autoinc %v, got autoinc %v", wantAutoInc, gotAutoInc) 387 } 388 } 389 390 func TestExecutorAddDropVindexDDL(t *testing.T) { 391 vschemaacl.AuthorizedDDLUsers = "%" 392 defer func() { 393 vschemaacl.AuthorizedDDLUsers = "" 394 }() 395 executor, sbc1, sbc2, sbclookup := createExecutorEnv() // nolint 396 ks := "TestExecutor" 397 session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) 398 vschemaUpdates := make(chan *vschemapb.SrvVSchema, 4) 399 executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) bool { 400 vschemaUpdates <- vschema 401 return true 402 }) 403 404 vschema := <-vschemaUpdates 405 _, ok := vschema.Keyspaces[ks].Vindexes["test_hash"] 406 require.False(t, ok, "test_hash should not exist in original vschema") 407 408 // Create a new vindex implicitly with the statement 409 stmt := "alter vschema on test add vindex test_hash (id) using hash " 410 _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 411 require.NoError(t, err) 412 413 _, vindex := waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) 414 require.Equal(t, "hash", vindex.Type) 415 416 _ = waitForColVindexes(t, ks, "test", []string{"test_hash"}, executor) 417 qr, err := executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) 418 require.NoError(t, err) 419 wantqr := &sqltypes.Result{ 420 Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), 421 Rows: [][]sqltypes.Value{ 422 buildVarCharRow("id", "test_hash", "hash", "", ""), 423 }, 424 } 425 utils.MustMatch(t, wantqr, qr) 426 427 // Drop it 428 stmt = "alter vschema on test drop vindex test_hash" 429 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 430 require.NoError(t, err) 431 432 _, _ = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) 433 _ = waitForColVindexes(t, ks, "test", []string{}, executor) 434 _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) 435 require.EqualError(t, err, "VT05005: table 'test' does not exist in keyspace 'TestExecutor'") 436 437 // add it again using the same syntax 438 stmt = "alter vschema on test add vindex test_hash (id) using hash " 439 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 440 require.NoError(t, err) 441 442 _, vindex = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) 443 require.Equal(t, "hash", vindex.Type) 444 445 _ = waitForColVindexes(t, ks, "test", []string{"test_hash"}, executor) 446 447 qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) 448 require.NoError(t, err) 449 wantqr = &sqltypes.Result{ 450 Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), 451 Rows: [][]sqltypes.Value{ 452 buildVarCharRow("id", "test_hash", "hash", "", ""), 453 }, 454 RowsAffected: 0, 455 } 456 utils.MustMatch(t, wantqr, qr) 457 458 // add another 459 stmt = "alter vschema on test add vindex test_lookup (c1,c2) using lookup with owner=`test`, from=`c1,c2`, table=test_lookup, to=keyspace_id" 460 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 461 require.NoError(t, err) 462 463 vschema, vindex = waitForVindex(t, ks, "test_lookup", vschemaUpdates, executor) 464 require.Equal(t, "lookup", vindex.Type) 465 466 if table, ok := vschema.Keyspaces[ks].Tables["test"]; ok { 467 if len(table.ColumnVindexes) != 2 { 468 t.Fatalf("table vindexes want 1 got %d", len(table.ColumnVindexes)) 469 } 470 if table.ColumnVindexes[1].Name != "test_lookup" { 471 t.Fatalf("table vindexes didn't contain test_lookup") 472 } 473 } else { 474 t.Fatalf("table test not defined in vschema") 475 } 476 477 qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) 478 require.NoError(t, err) 479 wantqr = &sqltypes.Result{ 480 Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), 481 Rows: [][]sqltypes.Value{ 482 buildVarCharRow("id", "test_hash", "hash", "", ""), 483 buildVarCharRow("c1, c2", "test_lookup", "lookup", "from=c1,c2; table=test_lookup; to=keyspace_id", "test"), 484 }, 485 } 486 utils.MustMatch(t, wantqr, qr) 487 488 stmt = "alter vschema on test add vindex test_hash_id2 (id2) using hash" 489 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 490 require.NoError(t, err) 491 492 vschema, vindex = waitForVindex(t, ks, "test_hash_id2", vschemaUpdates, executor) 493 require.Equal(t, "hash", vindex.Type) 494 495 if table, ok := vschema.Keyspaces[ks].Tables["test"]; ok { 496 if len(table.ColumnVindexes) != 3 { 497 t.Fatalf("table vindexes want 1 got %d", len(table.ColumnVindexes)) 498 } 499 if table.ColumnVindexes[2].Name != "test_hash_id2" { 500 t.Fatalf("table vindexes didn't contain test_hash_id2") 501 } 502 } else { 503 t.Fatalf("table test not defined in vschema") 504 } 505 506 qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) 507 require.NoError(t, err) 508 wantqr = &sqltypes.Result{ 509 Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), 510 Rows: [][]sqltypes.Value{ 511 buildVarCharRow("id", "test_hash", "hash", "", ""), 512 buildVarCharRow("c1, c2", "test_lookup", "lookup", "from=c1,c2; table=test_lookup; to=keyspace_id", "test"), 513 buildVarCharRow("id2", "test_hash_id2", "hash", "", ""), 514 }, 515 } 516 utils.MustMatch(t, wantqr, qr) 517 518 // drop one 519 stmt = "alter vschema on test drop vindex test_lookup" 520 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 521 require.NoError(t, err) 522 523 // wait for up to 50ms for it to disappear 524 deadline := time.Now().Add(50 * time.Millisecond) 525 for { 526 qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) 527 require.NoError(t, err) 528 wantqr = &sqltypes.Result{ 529 Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), 530 Rows: [][]sqltypes.Value{ 531 buildVarCharRow("id", "test_hash", "hash", "", ""), 532 buildVarCharRow("id2", "test_hash_id2", "hash", "", ""), 533 }, 534 } 535 if reflect.DeepEqual(qr, wantqr) { 536 break 537 } 538 539 if time.Now().After(deadline) { 540 require.Fail(t, "timed out waiting for test_lookup vindex to be removed") 541 } 542 time.Sleep(1 * time.Millisecond) 543 } 544 545 // use the newly created vindex on a new table 546 stmt = "alter vschema on test2 add vindex test_hash (id)" 547 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 548 require.NoError(t, err) 549 550 vschema, vindex = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) 551 require.Equal(t, "hash", vindex.Type) 552 553 table, ok := vschema.Keyspaces[ks].Tables["test2"] 554 require.Truef(t, ok, "table test2 not defined in vschema") 555 require.Len(t, table.ColumnVindexes, 1) 556 require.Equal(t, "test_hash", table.ColumnVindexes[0].Name) 557 558 // create an identical vindex definition on a different table 559 stmt = "alter vschema on test2 add vindex test_lookup (c1,c2) using lookup with owner=`test`, from=`c1,c2`, table=test_lookup, to=keyspace_id" 560 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 561 require.NoError(t, err) 562 563 vschema, vindex = waitForVindex(t, ks, "test_lookup", vschemaUpdates, executor) 564 require.Equal(t, "lookup", vindex.Type) 565 566 table, ok = vschema.Keyspaces[ks].Tables["test2"] 567 require.Truef(t, ok, "table test2 not defined in vschema") 568 require.Len(t, table.ColumnVindexes, 2) 569 require.Equal(t, "test_lookup", table.ColumnVindexes[1].Name) 570 571 qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test2", nil) 572 require.NoError(t, err) 573 wantqr = &sqltypes.Result{ 574 Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), 575 Rows: [][]sqltypes.Value{ 576 buildVarCharRow("id", "test_hash", "hash", "", ""), 577 buildVarCharRow("c1, c2", "test_lookup", "lookup", "from=c1,c2; table=test_lookup; to=keyspace_id", "test"), 578 }, 579 } 580 utils.MustMatch(t, wantqr, qr) 581 582 // now make sure we can create another vindex that references a table with dashes (i.e. escaping is necessary) 583 stmt = "alter vschema on test2 add vindex test_lookup_fqn(c1,c2) using consistent_lookup_unique with owner=`test`, from=`c1,c2`, table=`test-keyspace`.`lookup-fqn`, to=`keyspace_id`" 584 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 585 require.NoError(t, err) 586 587 _, vindex = waitForVindex(t, ks, "test_lookup_fqn", vschemaUpdates, executor) 588 require.Equal(t, "consistent_lookup_unique", vindex.Type) 589 require.Equal(t, "test", vindex.Owner) 590 require.Equal(t, "c1,c2", vindex.Params["from"]) 591 require.Equal(t, "`test-keyspace`.`lookup-fqn`", vindex.Params["table"]) 592 require.Equal(t, "keyspace_id", vindex.Params["to"]) 593 594 stmt = "alter vschema on test2 add vindex nonexistent (c1,c2)" 595 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 596 require.EqualError(t, err, "vindex nonexistent does not exist in keyspace TestExecutor") 597 598 stmt = "alter vschema on test2 add vindex test_hash (c1,c2) using lookup" 599 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 600 require.EqualError(t, err, "vindex test_hash defined with type hash not lookup") 601 602 stmt = "alter vschema on test2 add vindex test_lookup (c1,c2) using lookup with owner=xyz" 603 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 604 require.EqualError(t, err, "vindex test_lookup defined with owner test not xyz") 605 606 stmt = "alter vschema on test2 add vindex test_lookup (c1,c2) using lookup with owner=`test`, foo=bar" 607 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 608 require.EqualError(t, err, "vindex test_lookup defined with different parameters") 609 610 stmt = "alter vschema on nonexistent drop vindex test_lookup" 611 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 612 require.EqualError(t, err, "table TestExecutor.nonexistent not defined in vschema") 613 614 stmt = "alter vschema on nonexistent drop vindex test_lookup" 615 _, err = executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: "InvalidKeyspace"}), stmt, nil) 616 require.EqualError(t, err, "VT05003: unknown database 'InvalidKeyspace' in vschema") 617 618 stmt = "alter vschema on nowhere.nohow drop vindex test_lookup" 619 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 620 require.EqualError(t, err, "VT05003: unknown database 'nowhere' in vschema") 621 622 stmt = "alter vschema on test drop vindex test_lookup" 623 _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) 624 require.EqualError(t, err, "vindex test_lookup not defined in table TestExecutor.test") 625 626 // no queries should have gone to any tablets 627 wantCount := []int64{0, 0, 0} 628 gotCount := []int64{ 629 sbc1.ExecCount.Get(), 630 sbc2.ExecCount.Get(), 631 sbclookup.ExecCount.Get(), 632 } 633 utils.MustMatch(t, wantCount, gotCount) 634 } 635 636 func TestPlanExecutorVindexDDLACL(t *testing.T) { 637 // t.Skip("not yet planned") 638 executor, _, _, _ := createExecutorEnv() 639 ks := "TestExecutor" 640 session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) 641 642 ctxRedUser := callerid.NewContext(context.Background(), &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "redUser"}) 643 ctxBlueUser := callerid.NewContext(context.Background(), &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "blueUser"}) 644 645 // test that by default no users can perform the operation 646 stmt := "alter vschema create vindex test_hash using hash" 647 _, err := executor.Execute(ctxRedUser, "TestExecute", session, stmt, nil) 648 require.EqualError(t, err, `User 'redUser' is not authorized to perform vschema operations`) 649 650 _, err = executor.Execute(ctxBlueUser, "TestExecute", session, stmt, nil) 651 require.EqualError(t, err, `User 'blueUser' is not authorized to perform vschema operations`) 652 653 // test when all users are enabled 654 vschemaacl.AuthorizedDDLUsers = "%" 655 vschemaacl.Init() 656 _, err = executor.Execute(ctxRedUser, "TestExecute", session, stmt, nil) 657 if err != nil { 658 t.Errorf("unexpected error '%v'", err) 659 } 660 stmt = "alter vschema create vindex test_hash2 using hash" 661 _, err = executor.Execute(ctxBlueUser, "TestExecute", session, stmt, nil) 662 if err != nil { 663 t.Errorf("unexpected error '%v'", err) 664 } 665 666 // test when only one user is enabled 667 vschemaacl.AuthorizedDDLUsers = "orangeUser, blueUser, greenUser" 668 vschemaacl.Init() 669 _, err = executor.Execute(ctxRedUser, "TestExecute", session, stmt, nil) 670 require.EqualError(t, err, `User 'redUser' is not authorized to perform vschema operations`) 671 672 stmt = "alter vschema create vindex test_hash3 using hash" 673 _, err = executor.Execute(ctxBlueUser, "TestExecute", session, stmt, nil) 674 if err != nil { 675 t.Errorf("unexpected error '%v'", err) 676 } 677 678 // restore the disallowed state 679 vschemaacl.AuthorizedDDLUsers = "" 680 }