github.com/dolthub/go-mysql-server@v0.18.0/sql/analyzer/validation_rules_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 analyzer 16 17 import ( 18 "testing" 19 20 "github.com/stretchr/testify/require" 21 22 "github.com/dolthub/go-mysql-server/memory" 23 "github.com/dolthub/go-mysql-server/sql" 24 "github.com/dolthub/go-mysql-server/sql/analyzer/analyzererrors" 25 "github.com/dolthub/go-mysql-server/sql/expression" 26 "github.com/dolthub/go-mysql-server/sql/expression/function" 27 "github.com/dolthub/go-mysql-server/sql/expression/function/aggregation" 28 "github.com/dolthub/go-mysql-server/sql/plan" 29 "github.com/dolthub/go-mysql-server/sql/types" 30 "github.com/dolthub/go-mysql-server/sql/variables" 31 ) 32 33 func TestValidateResolved(t *testing.T) { 34 require := require.New(t) 35 36 vr := getValidationRule(validateResolvedId) 37 38 _, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector) 39 require.NoError(err) 40 41 _, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector) 42 require.Error(err) 43 } 44 45 func TestValidateOrderBy(t *testing.T) { 46 require := require.New(t) 47 48 vr := getValidationRule(validateOrderById) 49 50 _, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector) 51 require.NoError(err) 52 _, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector) 53 require.NoError(err) 54 55 _, _, err = vr.Apply(sql.NewEmptyContext(), nil, plan.NewSort( 56 []sql.SortField{{Column: aggregation.NewCount(nil), Order: sql.Descending}}, 57 nil, 58 ), nil, DefaultRuleSelector) 59 require.Error(err) 60 } 61 62 func TestValidateGroupBy(t *testing.T) { 63 variables.InitSystemVariables() 64 require := require.New(t) 65 66 vr := getValidationRule(validateGroupById) 67 68 _, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector) 69 require.NoError(err) 70 _, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector) 71 require.NoError(err) 72 73 childSchema := sql.NewPrimaryKeySchema(sql.Schema{ 74 {Name: "col1", Type: types.Text}, 75 {Name: "col2", Type: types.Int64}, 76 }) 77 78 db := memory.NewDatabase("db") 79 pro := memory.NewDBProvider(db) 80 ctx := newContext(pro) 81 82 child := memory.NewTable(db, "test", childSchema, nil) 83 84 rows := []sql.Row{ 85 sql.NewRow("col1_1", int64(1111)), 86 sql.NewRow("col1_1", int64(2222)), 87 sql.NewRow("col1_2", int64(4444)), 88 sql.NewRow("col1_1", int64(1111)), 89 sql.NewRow("col1_2", int64(4444)), 90 } 91 92 for _, r := range rows { 93 require.NoError(child.Insert(ctx, r)) 94 } 95 96 p := plan.NewGroupBy( 97 []sql.Expression{ 98 expression.NewAlias("alias", expression.NewGetField(0, types.Text, "col1", true)), 99 expression.NewGetField(0, types.Text, "col1", true), 100 aggregation.NewCount(expression.NewGetField(1, types.Int64, "col2", true)), 101 }, 102 []sql.Expression{ 103 expression.NewGetField(0, types.Text, "col1", true), 104 }, 105 plan.NewResolvedTable(child, nil, nil), 106 ) 107 108 _, _, err = vr.Apply(sql.NewEmptyContext(), nil, p, nil, DefaultRuleSelector) 109 require.NoError(err) 110 } 111 112 func TestValidateGroupByErr(t *testing.T) { 113 require := require.New(t) 114 vr := getValidationRule(validateGroupById) 115 116 _, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector) 117 require.NoError(err) 118 _, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector) 119 require.NoError(err) 120 121 childSchema := sql.NewPrimaryKeySchema(sql.Schema{ 122 {Name: "col1", Type: types.Text}, 123 {Name: "col2", Type: types.Int64}, 124 }) 125 126 db := memory.NewDatabase("db") 127 pro := memory.NewDBProvider(db) 128 ctx := newContext(pro) 129 130 child := memory.NewTable(db, "test", childSchema, nil) 131 132 rows := []sql.Row{ 133 sql.NewRow("col1_1", int64(1111)), 134 sql.NewRow("col1_1", int64(2222)), 135 sql.NewRow("col1_2", int64(4444)), 136 sql.NewRow("col1_1", int64(1111)), 137 sql.NewRow("col1_2", int64(4444)), 138 } 139 140 for _, r := range rows { 141 require.NoError(child.Insert(ctx, r)) 142 } 143 144 p := plan.NewGroupBy( 145 []sql.Expression{ 146 expression.NewGetField(0, types.Text, "col1", true), 147 expression.NewGetField(1, types.Int64, "col2", true), 148 }, 149 []sql.Expression{ 150 expression.NewGetField(0, types.Text, "col1", true), 151 }, 152 plan.NewResolvedTable(child, nil, nil), 153 ) 154 155 err = sql.SystemVariables.SetGlobal("sql_mode", "NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES") 156 require.NoError(err) 157 _, _, err = vr.Apply(ctx, nil, p, nil, DefaultRuleSelector) 158 require.Error(err) 159 } 160 161 func TestValidateSchemaSource(t *testing.T) { 162 db := memory.NewDatabase("db") 163 pro := memory.NewDBProvider(db) 164 ctx := newContext(pro) 165 166 testCases := []struct { 167 name string 168 node sql.Node 169 ok bool 170 }{ 171 { 172 "some random node", 173 plan.NewProject(nil, nil), 174 true, 175 }, 176 { 177 "table with valid schema", 178 plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{ 179 {Name: "foo", Source: "mytable"}, 180 {Name: "bar", Source: "mytable"}, 181 }), nil), nil, nil), 182 true, 183 }, 184 { 185 "table with invalid schema", 186 plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{ 187 {Name: "foo", Source: ""}, 188 {Name: "bar", Source: "something"}, 189 }), nil), nil, nil), 190 false, 191 }, 192 { 193 "table alias with table", 194 plan.NewTableAlias("foo", plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{ 195 {Name: "foo", Source: "mytable"}, 196 }), nil), nil, nil)), 197 true, 198 }, 199 { 200 "table alias with subquery", 201 plan.NewTableAlias( 202 "foo", 203 plan.NewProject( 204 []sql.Expression{ 205 expression.NewGetField(0, types.Text, "bar", false), 206 expression.NewGetField(1, types.Int64, "baz", false), 207 }, 208 nil, 209 ), 210 ), 211 true, 212 }, 213 } 214 215 rule := getValidationRule(validateSchemaSourceId) 216 for _, tt := range testCases { 217 t.Run(tt.name, func(t *testing.T) { 218 require := require.New(t) 219 _, _, err := rule.Apply(ctx, nil, tt.node, nil, DefaultRuleSelector) 220 if tt.ok { 221 require.NoError(err) 222 } else { 223 require.Error(err) 224 require.True(analyzererrors.ErrValidationSchemaSource.Is(err)) 225 } 226 }) 227 } 228 } 229 230 func TestValidateUnionSchemasMatch(t *testing.T) { 231 db := memory.NewDatabase("db") 232 pro := memory.NewDBProvider(db) 233 ctx := newContext(pro) 234 235 table := plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{ 236 {Name: "foo", Source: "mytable", Type: types.Text}, 237 {Name: "bar", Source: "mytable", Type: types.Int64}, 238 {Name: "rab", Source: "mytable", Type: types.Text}, 239 {Name: "zab", Source: "mytable", Type: types.Int64}, 240 {Name: "quuz", Source: "mytable", Type: types.Boolean}, 241 }), nil), nil, nil) 242 testCases := []struct { 243 name string 244 node sql.Node 245 ok bool 246 }{ 247 { 248 "some random node", 249 plan.NewProject( 250 []sql.Expression{ 251 expression.NewGetField(0, types.Text, "bar", false), 252 expression.NewGetField(1, types.Int64, "baz", false), 253 }, 254 table, 255 ), 256 true, 257 }, 258 { 259 "top-level union with matching schemas", 260 plan.NewSetOp( 261 plan.UnionType, 262 plan.NewProject( 263 []sql.Expression{ 264 expression.NewGetField(0, types.Text, "bar", false), 265 expression.NewGetField(1, types.Int64, "baz", false), 266 }, 267 table, 268 ), 269 plan.NewProject( 270 []sql.Expression{ 271 expression.NewGetField(2, types.Text, "rab", false), 272 expression.NewGetField(3, types.Int64, "zab", false), 273 }, 274 table, 275 ), 276 false, nil, nil, nil, 277 ), 278 true, 279 }, 280 { 281 "top-level union with longer left schema", 282 plan.NewSetOp( 283 plan.UnionType, 284 plan.NewProject( 285 []sql.Expression{ 286 expression.NewGetField(0, types.Text, "bar", false), 287 expression.NewGetField(1, types.Int64, "baz", false), 288 expression.NewGetField(4, types.Boolean, "quuz", false), 289 }, 290 table, 291 ), 292 plan.NewProject( 293 []sql.Expression{ 294 expression.NewGetField(2, types.Text, "rab", false), 295 expression.NewGetField(3, types.Int64, "zab", false), 296 }, 297 table, 298 ), 299 false, nil, nil, nil, 300 ), 301 false, 302 }, 303 { 304 "top-level union with longer right schema", 305 plan.NewSetOp( 306 plan.UnionType, 307 plan.NewProject( 308 []sql.Expression{ 309 expression.NewGetField(0, types.Text, "bar", false), 310 expression.NewGetField(1, types.Int64, "baz", false), 311 }, 312 table, 313 ), 314 plan.NewProject( 315 []sql.Expression{ 316 expression.NewGetField(2, types.Text, "rab", false), 317 expression.NewGetField(3, types.Int64, "zab", false), 318 expression.NewGetField(4, types.Boolean, "quuz", false), 319 }, 320 table, 321 ), 322 false, nil, nil, nil, 323 ), 324 false, 325 }, 326 { 327 "top-level union with mismatched type in schema", 328 plan.NewSetOp( 329 plan.UnionType, 330 plan.NewProject( 331 []sql.Expression{ 332 expression.NewGetField(0, types.Text, "bar", false), 333 expression.NewGetField(1, types.Int64, "baz", false), 334 }, 335 table, 336 ), 337 plan.NewProject( 338 []sql.Expression{ 339 expression.NewGetField(2, types.Text, "rab", false), 340 expression.NewGetField(3, types.Boolean, "zab", false), 341 }, 342 table, 343 ), 344 false, nil, nil, nil, 345 ), 346 false, 347 }, 348 { 349 "subquery union", 350 plan.NewSubqueryAlias( 351 "aliased", "select bar, baz from mytable union select rab, zab from mytable", 352 plan.NewSetOp( 353 plan.UnionType, 354 plan.NewProject( 355 []sql.Expression{ 356 expression.NewGetField(0, types.Text, "bar", false), 357 expression.NewGetField(1, types.Int64, "baz", false), 358 }, 359 table, 360 ), 361 plan.NewProject( 362 []sql.Expression{ 363 expression.NewGetField(2, types.Text, "rab", false), 364 expression.NewGetField(3, types.Boolean, "zab", false), 365 }, 366 table, 367 ), 368 false, nil, nil, nil), 369 ), 370 false, 371 }, 372 } 373 374 rule := getValidationRule(validateUnionSchemasMatchId) 375 for _, tt := range testCases { 376 t.Run(tt.name, func(t *testing.T) { 377 require := require.New(t) 378 _, _, err := rule.Apply(ctx, nil, tt.node, nil, DefaultRuleSelector) 379 if tt.ok { 380 require.NoError(err) 381 } else { 382 require.Error(err) 383 require.True(analyzererrors.ErrUnionSchemasMatch.Is(err)) 384 } 385 }) 386 } 387 } 388 389 func TestValidateOperands(t *testing.T) { 390 testCases := []struct { 391 name string 392 node sql.Node 393 ok bool 394 }{ 395 { 396 "project with no tuple", 397 plan.NewProject([]sql.Expression{ 398 expression.NewLiteral(1, types.Int64), 399 }, nil), 400 true, 401 }, 402 { 403 "project with a 1 elem tuple", 404 plan.NewProject([]sql.Expression{ 405 expression.NewTuple( 406 expression.NewLiteral(1, types.Int64), 407 ), 408 }, nil), 409 true, 410 }, 411 { 412 "project with a 2 elem tuple", 413 plan.NewProject([]sql.Expression{ 414 expression.NewTuple( 415 expression.NewLiteral(1, types.Int64), 416 expression.NewLiteral(2, types.Int64), 417 ), 418 }, nil), 419 false, 420 }, 421 { 422 "distinct with a 2 elem tuple inside the project", 423 plan.NewDistinct( 424 plan.NewProject([]sql.Expression{ 425 expression.NewTuple( 426 expression.NewLiteral(1, types.Int64), 427 expression.NewLiteral(2, types.Int64), 428 ), 429 }, nil)), 430 false, 431 }, 432 { 433 "alias with a tuple", 434 plan.NewProject( 435 []sql.Expression{ 436 expression.NewAlias("foo", expression.NewTuple( 437 expression.NewLiteral(1, types.Int64), 438 expression.NewLiteral(2, types.Int64), 439 )), 440 }, 441 plan.NewUnresolvedTable("dual", ""), 442 ), 443 false, 444 }, 445 { 446 "groupby with no tuple", 447 plan.NewGroupBy([]sql.Expression{ 448 expression.NewLiteral(1, types.Int64), 449 }, nil, nil), 450 true, 451 }, 452 { 453 "groupby with a 1 elem tuple", 454 plan.NewGroupBy([]sql.Expression{ 455 expression.NewTuple( 456 expression.NewLiteral(1, types.Int64), 457 ), 458 }, nil, nil), 459 true, 460 }, 461 { 462 "groupby with a 2 elem tuple", 463 plan.NewGroupBy([]sql.Expression{ 464 expression.NewTuple( 465 expression.NewLiteral(1, types.Int64), 466 expression.NewLiteral(1, types.Int64), 467 ), 468 }, nil, nil), 469 false, 470 }, 471 { 472 "validate subquery columns", 473 plan.NewProject([]sql.Expression{ 474 plan.NewSubquery(plan.NewProject( 475 []sql.Expression{ 476 lit(1), 477 lit(2), 478 }, 479 dummyNode{true}, 480 ), "select 1, 2"), 481 }, dummyNode{true}), 482 false, 483 }, 484 } 485 486 rule := getValidationRule(validateOperandsId) 487 for _, tt := range testCases { 488 t.Run(tt.name, func(t *testing.T) { 489 require := require.New(t) 490 _, _, err := rule.Apply(sql.NewEmptyContext(), nil, tt.node, nil, DefaultRuleSelector) 491 if tt.ok { 492 require.NoError(err) 493 } else { 494 require.Error(err) 495 require.True(sql.ErrInvalidOperandColumns.Is(err)) 496 } 497 }) 498 } 499 } 500 501 func TestValidateIndexCreation(t *testing.T) { 502 db := memory.NewDatabase("db") 503 pro := memory.NewDBProvider(db) 504 ctx := newContext(pro) 505 506 table := memory.NewTable(db, "foo", sql.NewPrimaryKeySchema(sql.Schema{ 507 {Name: "a", Source: "foo"}, 508 {Name: "b", Source: "foo"}, 509 }), nil) 510 511 testCases := []struct { 512 name string 513 node sql.Node 514 ok bool 515 }{ 516 { 517 "columns from another table", 518 plan.NewCreateIndex( 519 "idx", plan.NewResolvedTable(table, nil, nil), 520 []sql.Expression{expression.NewEquals( 521 expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "a", false), 522 expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "bar", "b", false), 523 )}, 524 "", 525 make(map[string]string), 526 ), 527 false, 528 }, 529 { 530 "columns that don't exist", 531 plan.NewCreateIndex( 532 "idx", plan.NewResolvedTable(table, nil, nil), 533 []sql.Expression{expression.NewEquals( 534 expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "a", false), 535 expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "c", false), 536 )}, 537 "", 538 make(map[string]string), 539 ), 540 false, 541 }, 542 { 543 "columns only from table", 544 plan.NewCreateIndex( 545 "idx", plan.NewResolvedTable(table, nil, nil), 546 []sql.Expression{expression.NewEquals( 547 expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "a", false), 548 expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "b", false), 549 )}, 550 "", 551 make(map[string]string), 552 ), 553 true, 554 }, 555 } 556 557 rule := getValidationRule(validateIndexCreationId) 558 for _, tt := range testCases { 559 t.Run(tt.name, func(t *testing.T) { 560 require := require.New(t) 561 _, _, err := rule.Apply(ctx, nil, tt.node, nil, DefaultRuleSelector) 562 if tt.ok { 563 require.NoError(err) 564 } else { 565 require.Error(err) 566 require.True(analyzererrors.ErrUnknownIndexColumns.Is(err)) 567 } 568 }) 569 } 570 } 571 572 func mustFunc(e sql.Expression, err error) sql.Expression { 573 if err != nil { 574 panic(err) 575 } 576 return e 577 } 578 579 func TestValidateIntervalUsage(t *testing.T) { 580 testCases := []struct { 581 name string 582 node sql.Node 583 ok bool 584 }{ 585 { 586 "date add", 587 plan.NewProject( 588 []sql.Expression{ 589 mustFunc(function.NewDateAdd( 590 expression.NewLiteral("2018-05-01", types.LongText), 591 expression.NewInterval( 592 expression.NewLiteral(int64(1), types.Int64), 593 "DAY", 594 ), 595 )), 596 }, 597 plan.NewUnresolvedTable("dual", ""), 598 ), 599 true, 600 }, 601 { 602 "date sub", 603 plan.NewProject( 604 []sql.Expression{ 605 mustFunc(function.NewDateSub( 606 expression.NewLiteral("2018-05-01", types.LongText), 607 expression.NewInterval( 608 expression.NewLiteral(int64(1), types.Int64), 609 "DAY", 610 ), 611 )), 612 }, 613 plan.NewUnresolvedTable("dual", ""), 614 ), 615 true, 616 }, 617 { 618 "+ op", 619 plan.NewProject( 620 []sql.Expression{ 621 expression.NewPlus( 622 expression.NewLiteral("2018-05-01", types.LongText), 623 expression.NewInterval( 624 expression.NewLiteral(int64(1), types.Int64), 625 "DAY", 626 ), 627 ), 628 }, 629 plan.NewUnresolvedTable("dual", ""), 630 ), 631 true, 632 }, 633 { 634 "- op", 635 plan.NewProject( 636 []sql.Expression{ 637 expression.NewMinus( 638 expression.NewLiteral("2018-05-01", types.LongText), 639 expression.NewInterval( 640 expression.NewLiteral(int64(1), types.Int64), 641 "DAY", 642 ), 643 ), 644 }, 645 plan.NewUnresolvedTable("dual", ""), 646 ), 647 true, 648 }, 649 { 650 "invalid", 651 plan.NewProject( 652 []sql.Expression{ 653 expression.NewInterval( 654 expression.NewLiteral(int64(1), types.Int64), 655 "DAY", 656 ), 657 }, 658 plan.NewUnresolvedTable("dual", ""), 659 ), 660 false, 661 }, 662 { 663 "alias", 664 plan.NewProject( 665 []sql.Expression{ 666 expression.NewAlias("foo", expression.NewInterval( 667 expression.NewLiteral(int64(1), types.Int64), 668 "DAY", 669 )), 670 }, 671 plan.NewUnresolvedTable("dual", ""), 672 ), 673 false, 674 }, 675 } 676 677 for _, tt := range testCases { 678 t.Run(tt.name, func(t *testing.T) { 679 require := require.New(t) 680 681 _, _, err := validateIntervalUsage(sql.NewEmptyContext(), nil, tt.node, nil, DefaultRuleSelector) 682 if tt.ok { 683 require.NoError(err) 684 } else { 685 require.Error(err) 686 require.True(analyzererrors.ErrIntervalInvalidUse.Is(err)) 687 } 688 }) 689 } 690 } 691 692 func TestValidateSubqueryColumns(t *testing.T) { 693 t.Skip() 694 695 require := require.New(t) 696 697 db := memory.NewDatabase("db") 698 pro := memory.NewDBProvider(db) 699 ctx := newContext(pro) 700 701 table := memory.NewTable(db, "test", sql.NewPrimaryKeySchema(sql.Schema{ 702 {Name: "foo", Type: types.Text}, 703 }), nil) 704 subTable := memory.NewTable(db, "subtest", sql.NewPrimaryKeySchema(sql.Schema{ 705 {Name: "bar", Type: types.Text}, 706 }), nil) 707 708 var node sql.Node 709 node = plan.NewProject([]sql.Expression{ 710 plan.NewSubquery(plan.NewFilter(expression.NewGreaterThan( 711 expression.NewGetField(0, types.Boolean, "foo", false), 712 lit(1), 713 ), plan.NewProject( 714 []sql.Expression{ 715 expression.NewGetField(1, types.Boolean, "bar", false), 716 }, 717 plan.NewResolvedTable(subTable, nil, nil), 718 )), "select bar from subtest where foo > 1"), 719 }, plan.NewResolvedTable(table, nil, nil)) 720 721 _, _, err := validateSubqueryColumns(ctx, nil, node, nil, DefaultRuleSelector) 722 require.NoError(err) 723 724 node = plan.NewProject([]sql.Expression{ 725 plan.NewSubquery(plan.NewFilter(expression.NewGreaterThan( 726 expression.NewGetField(1, types.Boolean, "foo", false), 727 lit(1), 728 ), plan.NewProject( 729 []sql.Expression{ 730 expression.NewGetField(2, types.Boolean, "bar", false), 731 }, 732 plan.NewResolvedTable(subTable, nil, nil), 733 )), "select bar from subtest where foo > 1"), 734 }, plan.NewResolvedTable(table, nil, nil)) 735 736 _, _, err = validateSubqueryColumns(ctx, nil, node, nil, DefaultRuleSelector) 737 require.Error(err) 738 require.True(analyzererrors.ErrSubqueryFieldIndex.Is(err)) 739 740 node = plan.NewProject([]sql.Expression{ 741 plan.NewSubquery(plan.NewProject( 742 []sql.Expression{ 743 lit(1), 744 }, 745 dummyNode{true}, 746 ), "select 1"), 747 }, dummyNode{true}) 748 749 _, _, err = validateSubqueryColumns(ctx, nil, node, nil, DefaultRuleSelector) 750 require.NoError(err) 751 752 } 753 754 type dummyNode struct{ resolved bool } 755 756 var _ sql.Node = dummyNode{} 757 var _ sql.CollationCoercible = dummyNode{} 758 759 func (n dummyNode) String() string { return "dummynode" } 760 func (n dummyNode) Resolved() bool { return n.resolved } 761 func (dummyNode) IsReadOnly() bool { return true } 762 func (dummyNode) Schema() sql.Schema { return nil } 763 func (dummyNode) Children() []sql.Node { return nil } 764 func (dummyNode) RowIter(*sql.Context, sql.Row) (sql.RowIter, error) { return nil, nil } 765 func (dummyNode) WithChildren(...sql.Node) (sql.Node, error) { return nil, nil } 766 func (dummyNode) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 767 return true 768 } 769 func (dummyNode) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 770 return sql.Collation_binary, 7 771 } 772 773 func getValidationRule(id RuleId) Rule { 774 for _, rule := range DefaultValidationRules { 775 if rule.Id == id { 776 return rule 777 } 778 } 779 panic("missing rule") 780 }