github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/sqlselect_test.go (about) 1 // Copyright 2020 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 sqle 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 gmstypes "github.com/dolthub/go-mysql-server/sql/types" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 27 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 28 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 29 "github.com/dolthub/dolt/go/libraries/doltcore/dtestutils" 30 "github.com/dolthub/dolt/go/libraries/doltcore/env" 31 "github.com/dolthub/dolt/go/libraries/doltcore/ref" 32 "github.com/dolthub/dolt/go/libraries/doltcore/row" 33 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 34 "github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo" 35 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtables" 36 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/json" 37 "github.com/dolthub/dolt/go/store/datas" 38 "github.com/dolthub/dolt/go/store/types" 39 ) 40 41 // Set to the name of a single test to run just that test, useful for debugging 42 const singleSelectQueryTest = "" //"Natural join with join clause" 43 44 // Set to false to run tests known to be broken 45 const skipBrokenSelect = true 46 47 // Structure for a test of a select query 48 type SelectTest struct { 49 // The name of this test. Names should be unique and descriptive. 50 Name string 51 // The query to run, excluding an ending semicolon 52 Query string 53 // The schema of the result of the query, nil if an error is expected 54 ExpectedSchema schema.Schema 55 // The schema of the result of the query, nil if an error is expected. Mutually exclusive with ExpectedSchema. Use if 56 // the schema is difficult to specify with dolt schemas. 57 ExpectedSqlSchema sql.Schema 58 // The rows this query should return, nil if an error is expected 59 ExpectedRows []sql.Row 60 // An expected error string 61 ExpectedErr string 62 // Setup logic to run before executing this test, after initial tables have been created and populated 63 AdditionalSetup SetupFn 64 // Whether to skip this test on SqlEngine (go-mysql-server) execution. 65 // Over time, this should become false for every query. 66 SkipOnSqlEngine bool 67 } 68 69 // We are doing structural equality tests on time.Time values in some of these 70 // tests. The SQL value layer works with times in time.Local location, but 71 // go standard library will return different values (which will have the same 72 // behavior) depending on whether detailed timezone information has been loaded 73 // for time.Local already. Here, we always load the detailed information so 74 // that our structural equality tests will be reliable. 75 var loadedLocalLocation *time.Location 76 77 func LoadedLocalLocation() *time.Location { 78 var err error 79 loadedLocalLocation, err = time.LoadLocation(time.Local.String()) 80 if err != nil { 81 panic(err) 82 } 83 if loadedLocalLocation == nil { 84 panic("nil LoadedLocalLocation " + time.Local.String()) 85 } 86 return loadedLocalLocation 87 } 88 89 // BasicSelectTests cover basic select statement features and error handling 90 func BasicSelectTests() []SelectTest { 91 var headCommitHash string 92 switch types.Format_Default { 93 case types.Format_DOLT: 94 headCommitHash = "ias4mf52sgeig337ce2le7ov9vpltppr" 95 case types.Format_LD_1: 96 headCommitHash = "73hc2robs4v0kt9taoe3m5hd49dmrgun" 97 } 98 99 return []SelectTest{ 100 { 101 Name: "select * on primary key", 102 Query: "select * from people where id = 2", 103 ExpectedRows: ToSqlRows(PeopleTestSchema, Bart), 104 ExpectedSchema: CompressSchema(PeopleTestSchema), 105 }, 106 { 107 Name: "select * ", 108 Query: "select * from people", 109 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Moe, Barney), 110 ExpectedSchema: CompressSchema(PeopleTestSchema), 111 }, 112 { 113 Name: "select *, limit 1", 114 Query: "select * from people limit 1", 115 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 116 ExpectedSchema: CompressSchema(PeopleTestSchema), 117 }, 118 { 119 Name: "select *, limit 1 offset 0", 120 Query: "select * from people limit 0,1", 121 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 122 ExpectedSchema: CompressSchema(PeopleTestSchema), 123 }, 124 { 125 Name: "select *, limit 1 offset 1", 126 Query: "select * from people limit 1 offset 1;", 127 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge), 128 ExpectedSchema: CompressSchema(PeopleTestSchema), 129 }, 130 { 131 Name: "select *, limit 1 offset 5", 132 Query: "select * from people limit 5,1", 133 ExpectedRows: ToSqlRows(PeopleTestSchema, Barney), 134 ExpectedSchema: CompressSchema(PeopleTestSchema), 135 }, 136 { 137 Name: "select *, limit 1 offset 6", 138 Query: "select * from people limit 6,1", 139 ExpectedRows: ToSqlRows(PeopleTestSchema), 140 ExpectedSchema: CompressSchema(PeopleTestSchema), 141 }, 142 { 143 Name: "select *, limit 0", 144 Query: "select * from people limit 0", 145 ExpectedRows: ToSqlRows(PeopleTestSchema), 146 ExpectedSchema: CompressSchema(PeopleTestSchema), 147 }, 148 { 149 Name: "select *, limit 0 offset 0", 150 Query: "select * from people limit 0,0", 151 ExpectedRows: ToSqlRows(PeopleTestSchema), 152 ExpectedSchema: CompressSchema(PeopleTestSchema), 153 }, 154 { 155 Name: "select *, limit -1", 156 Query: "select * from people limit -1", 157 ExpectedErr: "Limit must be >= 0 if supplied", 158 }, 159 { 160 Name: "select *, offset -1", 161 Query: "select * from people limit -1,1", 162 ExpectedErr: "Offset must be >= 0 if supplied", 163 }, 164 { 165 Name: "select *, limit 100", 166 Query: "select * from people limit 100", 167 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Moe, Barney), 168 ExpectedSchema: CompressSchema(PeopleTestSchema), 169 }, 170 { 171 Name: "select *, where < int", 172 Query: "select * from people where age < 40", 173 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa), 174 ExpectedSchema: CompressSchema(PeopleTestSchema), 175 }, 176 { 177 Name: "select *, where < int, limit 1", 178 Query: "select * from people where age < 40 limit 1", 179 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge), 180 ExpectedSchema: CompressSchema(PeopleTestSchema), 181 }, 182 { 183 Name: "select *, where < int, limit 2", 184 Query: "select * from people where age < 40 limit 2", 185 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge, Bart), 186 ExpectedSchema: CompressSchema(PeopleTestSchema), 187 }, 188 { 189 Name: "select *, where < int, limit 100", 190 Query: "select * from people where age < 40 limit 100", 191 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa), 192 ExpectedSchema: CompressSchema(PeopleTestSchema), 193 }, 194 { 195 Name: "select *, order by int", 196 Query: "select * from people order by id", 197 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Moe, Barney), 198 ExpectedSchema: CompressSchema(PeopleTestSchema), 199 }, 200 { 201 Name: "select *, order by int desc", 202 Query: "select * from people order by id desc", 203 ExpectedRows: ToSqlRows(PeopleTestSchema, Barney, Moe, Lisa, Bart, Marge, Homer), 204 ExpectedSchema: CompressSchema(PeopleTestSchema), 205 }, 206 { 207 Name: "select *, order by float", 208 Query: "select * from people order by rating", 209 ExpectedRows: ToSqlRows(PeopleTestSchema, Barney, Moe, Marge, Homer, Bart, Lisa), 210 ExpectedSchema: CompressSchema(PeopleTestSchema), 211 }, 212 { 213 Name: "select *, order by string", 214 Query: "select * from people order by first_name", 215 ExpectedRows: ToSqlRows(PeopleTestSchema, Barney, Bart, Homer, Lisa, Marge, Moe), 216 ExpectedSchema: CompressSchema(PeopleTestSchema), 217 }, 218 { 219 Name: "select *, order by string,string", 220 Query: "select * from people order by last_name desc, first_name asc", 221 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe, Bart, Homer, Lisa, Marge, Barney), 222 ExpectedSchema: CompressSchema(PeopleTestSchema), 223 }, 224 { 225 Name: "select *, order by with limit", 226 Query: "select * from people order by first_name limit 2", 227 ExpectedRows: ToSqlRows(PeopleTestSchema, Barney, Bart), 228 ExpectedSchema: CompressSchema(PeopleTestSchema), 229 }, 230 { 231 Name: "select *, order by string,string with limit", 232 Query: "select * from people order by last_name desc, first_name asc limit 2", 233 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe, Bart), 234 ExpectedSchema: CompressSchema(PeopleTestSchema), 235 }, 236 { 237 Name: "select *, where > int reversed", 238 Query: "select * from people where 40 > age", 239 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa), 240 ExpectedSchema: CompressSchema(PeopleTestSchema), 241 }, 242 { 243 Name: "select *, where <= int", 244 Query: "select * from people where age <= 40", 245 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Barney), 246 ExpectedSchema: CompressSchema(PeopleTestSchema), 247 }, 248 { 249 Name: "select *, where >= int reversed", 250 Query: "select * from people where 40 >= age", 251 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Barney), 252 ExpectedSchema: CompressSchema(PeopleTestSchema), 253 }, 254 { 255 Name: "select *, where > int", 256 Query: "select * from people where age > 40", 257 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe), 258 ExpectedSchema: CompressSchema(PeopleTestSchema), 259 }, 260 { 261 Name: "select *, where < int reversed", 262 Query: "select * from people where 40 < age", 263 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe), 264 ExpectedSchema: CompressSchema(PeopleTestSchema), 265 }, 266 { 267 Name: "select *, where >= int", 268 Query: "select * from people where age >= 40", 269 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Moe, Barney), 270 ExpectedSchema: CompressSchema(PeopleTestSchema), 271 }, 272 { 273 Name: "select *, where <= int reversed", 274 Query: "select * from people where 40 <= age", 275 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Moe, Barney), 276 ExpectedSchema: CompressSchema(PeopleTestSchema), 277 }, 278 { 279 Name: "select *, where > string", 280 Query: "select * from people where last_name > 'Simpson'", 281 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe), 282 ExpectedSchema: CompressSchema(PeopleTestSchema), 283 }, 284 { 285 Name: "select *, where < string", 286 Query: "select * from people where last_name < 'Simpson'", 287 ExpectedRows: ToSqlRows(PeopleTestSchema, Barney), 288 ExpectedSchema: CompressSchema(PeopleTestSchema), 289 }, 290 { 291 Name: "select *, where = string", 292 Query: "select * from people where last_name = 'Simpson'", 293 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa), 294 ExpectedSchema: CompressSchema(PeopleTestSchema), 295 }, 296 { 297 Name: "select *, where > float", 298 Query: "select * from people where rating > 8.0 order by id", 299 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Bart, Lisa), 300 ExpectedSchema: CompressSchema(PeopleTestSchema), 301 }, 302 { 303 Name: "select *, where < float", 304 Query: "select * from people where rating < 8.0", 305 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe, Barney), 306 ExpectedSchema: CompressSchema(PeopleTestSchema), 307 }, 308 { 309 Name: "select *, where = float", 310 Query: "select * from people where rating = 8.0", 311 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge), 312 ExpectedSchema: CompressSchema(PeopleTestSchema), 313 }, 314 { 315 Name: "select *, where < float reversed", 316 Query: "select * from people where 8.0 < rating", 317 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Bart, Lisa), 318 ExpectedSchema: CompressSchema(PeopleTestSchema), 319 }, 320 { 321 Name: "select *, where > float reversed", 322 Query: "select * from people where 8.0 > rating", 323 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe, Barney), 324 ExpectedSchema: CompressSchema(PeopleTestSchema), 325 }, 326 { 327 Name: "select *, where = float reversed", 328 Query: "select * from people where 8.0 = rating", 329 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge), 330 ExpectedSchema: CompressSchema(PeopleTestSchema), 331 }, 332 { 333 Name: "select *, where bool = ", 334 Query: "select * from people where is_married = true", 335 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge), 336 ExpectedSchema: CompressSchema(PeopleTestSchema), 337 }, 338 { 339 Name: "select *, where bool = false ", 340 Query: "select * from people where is_married = false", 341 ExpectedRows: ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney), 342 ExpectedSchema: CompressSchema(PeopleTestSchema), 343 }, 344 { 345 Name: "select *, where bool <> ", 346 Query: "select * from people where is_married <> false", 347 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge), 348 ExpectedSchema: CompressSchema(PeopleTestSchema), 349 }, 350 { 351 Name: "select *, where bool", 352 Query: "select * from people where is_married", 353 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge), 354 ExpectedSchema: CompressSchema(PeopleTestSchema), 355 }, 356 { 357 Name: "select *, and clause", 358 Query: "select * from people where is_married and age > 38", 359 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 360 ExpectedSchema: CompressSchema(PeopleTestSchema), 361 }, 362 { 363 Name: "select *, or clause", 364 Query: "select * from people where is_married or age < 20", 365 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa), 366 ExpectedSchema: CompressSchema(PeopleTestSchema), 367 }, 368 { 369 Name: "select *, in clause string", 370 Query: "select * from people where first_name in ('Homer', 'Marge')", 371 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge), 372 ExpectedSchema: CompressSchema(PeopleTestSchema), 373 }, 374 { 375 Name: "select *, in clause integer", 376 Query: "select * from people where age in (-10, 40)", 377 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 378 ExpectedSchema: CompressSchema(PeopleTestSchema), 379 }, 380 { 381 Name: "select *, in clause float", 382 Query: "select * from people where rating in (-10.0, 8.5)", 383 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 384 ExpectedSchema: CompressSchema(PeopleTestSchema), 385 }, 386 { 387 Name: "select *, in clause, mixed types", 388 Query: "select * from people where first_name in ('Homer', 40)", 389 ExpectedSchema: CompressSchema(PeopleTestSchema), 390 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 391 }, 392 { 393 Name: "select *, in clause, mixed numeric types", 394 Query: "select * from people where age in (-10.0, 40)", 395 ExpectedSchema: CompressSchema(PeopleTestSchema), 396 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 397 }, 398 { 399 Name: "select *, not in clause", 400 Query: "select * from people where first_name not in ('Homer', 'Marge')", 401 ExpectedRows: ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney), 402 ExpectedSchema: CompressSchema(PeopleTestSchema), 403 }, 404 { 405 Name: "select *, in clause single element", 406 Query: "select * from people where first_name in ('Homer')", 407 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 408 ExpectedSchema: CompressSchema(PeopleTestSchema), 409 }, 410 { 411 Name: "select *, in clause single type mismatch", 412 Query: "select * from people where first_name in (1.0)", 413 ExpectedRows: ToSqlRows(PeopleTestSchema), 414 ExpectedSchema: CompressSchema(PeopleTestSchema), 415 }, 416 { 417 Name: "select *, is null clause ", 418 Query: "select * from people where uuid is null", 419 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 420 ExpectedSchema: CompressSchema(PeopleTestSchema), 421 }, 422 { 423 Name: "select *, is not null clause ", 424 Query: "select * from people where uuid is not null", 425 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa, Moe, Barney), 426 ExpectedSchema: CompressSchema(PeopleTestSchema), 427 }, 428 { 429 Name: "select *, is true clause ", 430 Query: "select * from people where is_married is true", 431 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge), 432 ExpectedSchema: CompressSchema(PeopleTestSchema), 433 }, 434 { 435 Name: "select *, is not true clause ", 436 Query: "select * from people where is_married is not true", 437 ExpectedRows: ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney), 438 ExpectedSchema: CompressSchema(PeopleTestSchema), 439 }, 440 { 441 Name: "select *, is false clause ", 442 Query: "select * from people where is_married is false", 443 ExpectedRows: ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney), 444 ExpectedSchema: CompressSchema(PeopleTestSchema), 445 }, 446 { 447 Name: "select *, is not false clause ", 448 Query: "select * from people where is_married is not false", 449 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Marge), 450 ExpectedSchema: CompressSchema(PeopleTestSchema), 451 }, 452 { 453 Name: "select *, is true clause on non-bool column", 454 Query: "select * from people where age is true", 455 ExpectedRows: ToSqlRows(PeopleTestSchema, AllPeopleRows...), 456 ExpectedSchema: CompressSchema(PeopleTestSchema), 457 }, 458 { 459 Name: "binary expression in select", 460 Query: "select age + 1 as a from people where is_married order by a", 461 ExpectedRows: ToSqlRows(NewResultSetSchema("a", types.IntKind), NewResultSetRow(types.Int(39)), NewResultSetRow(types.Int(41))), 462 ExpectedSchema: NewResultSetSchema("a", types.IntKind), 463 }, 464 { 465 Name: "and expression in select", 466 Query: "select is_married and age >= 40 from people where last_name = 'Simpson' order by id limit 2", 467 ExpectedRows: []sql.Row{{true}, {false}}, 468 ExpectedSqlSchema: sql.Schema{ 469 &sql.Column{Name: "is_married and age >= 40", Type: gmstypes.Boolean}, 470 }, 471 }, 472 { 473 Name: "or expression in select", 474 Query: "select first_name, age <= 10 or age >= 40 as not_marge from people where last_name = 'Simpson' order by id desc", 475 ExpectedRows: []sql.Row{ 476 {"Lisa", true}, 477 {"Bart", true}, 478 {"Marge", false}, 479 {"Homer", true}, 480 }, 481 ExpectedSqlSchema: sql.Schema{ 482 &sql.Column{Name: "first_name", Type: typeinfo.StringDefaultType.ToSqlType()}, 483 &sql.Column{Name: "not_marge", Type: gmstypes.Boolean}, 484 }, 485 }, 486 { 487 Name: "unary expression in select", 488 Query: "select -age as age from people where is_married order by age", 489 ExpectedRows: ToSqlRows(NewResultSetSchema("age", types.IntKind), NewResultSetRow(types.Int(-40)), NewResultSetRow(types.Int(-38))), 490 ExpectedSchema: NewResultSetSchema("age", types.IntKind), 491 }, 492 { 493 Name: "unary expression in select, alias named after column", 494 Query: "select -age as age from people where is_married order by people.age", 495 ExpectedRows: ToSqlRows(NewResultSetSchema("age", types.IntKind), NewResultSetRow(types.Int(-38)), NewResultSetRow(types.Int(-40))), 496 ExpectedSchema: NewResultSetSchema("age", types.IntKind), 497 SkipOnSqlEngine: true, // this seems to be a bug in the engine 498 }, 499 { 500 Name: "select *, -column", 501 Query: "select * from people where -rating = -8.5", 502 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 503 ExpectedSchema: CompressSchema(PeopleTestSchema), 504 }, 505 { 506 Name: "select *, -column, string type", 507 Query: "select * from people where -first_name = 'Homer'", 508 ExpectedSchema: CompressSchema(PeopleTestSchema), 509 ExpectedRows: ToSqlRows(PeopleTestSchema, AllPeopleRows...), // A little weird, but correct due to mysql type conversion rules (both expression evaluate to 0 after conversion) 510 }, 511 { 512 Name: "select *, binary + in where", 513 Query: "select * from people where age + 1 = 41", 514 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 515 ExpectedSchema: CompressSchema(PeopleTestSchema), 516 }, 517 { 518 Name: "select *, binary - in where", 519 Query: "select * from people where age - 1 = 39", 520 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 521 ExpectedSchema: CompressSchema(PeopleTestSchema), 522 }, 523 { 524 Name: "select *, binary / in where", 525 Query: "select * from people where age / 2 = 20", 526 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 527 ExpectedSchema: CompressSchema(PeopleTestSchema), 528 }, 529 { 530 Name: "select *, binary * in where", 531 Query: "select * from people where age * 2 = 80", 532 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 533 ExpectedSchema: CompressSchema(PeopleTestSchema), 534 }, 535 { 536 Name: "select *, binary % in where", 537 Query: "select * from people where age % 4 = 0", 538 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Lisa, Moe, Barney), 539 ExpectedSchema: CompressSchema(PeopleTestSchema), 540 }, 541 { 542 Name: "select *, complex binary expr in where", 543 Query: "select * from people where age / 4 + 2 * 2 = 14", 544 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Barney), 545 ExpectedSchema: CompressSchema(PeopleTestSchema), 546 }, 547 { 548 Name: "select *, binary + in where type mismatch", 549 Query: "select * from people where first_name + 1 = 41", 550 ExpectedRows: ToSqlRows(PeopleTestSchema), 551 ExpectedSchema: CompressSchema(PeopleTestSchema), 552 }, 553 { 554 Name: "select *, binary - in where type mismatch", 555 Query: "select * from people where first_name - 1 = 39", 556 ExpectedRows: ToSqlRows(PeopleTestSchema), 557 ExpectedSchema: CompressSchema(PeopleTestSchema), 558 }, 559 { 560 Name: "select *, binary / in where type mismatch", 561 Query: "select * from people where first_name / 2 = 20", 562 ExpectedRows: ToSqlRows(PeopleTestSchema), 563 ExpectedSchema: CompressSchema(PeopleTestSchema), 564 }, 565 { 566 Name: "select *, binary * in where type mismatch", 567 Query: "select * from people where first_name * 2 = 80", 568 ExpectedRows: ToSqlRows(PeopleTestSchema), 569 ExpectedSchema: CompressSchema(PeopleTestSchema), 570 }, 571 { 572 Name: "select *, binary % in where type mismatch", 573 Query: "select * from people where first_name % 4 = 0", 574 ExpectedRows: ToSqlRows(PeopleTestSchema, AllPeopleRows...), // invalid value is considered as 0 575 ExpectedSchema: CompressSchema(PeopleTestSchema), 576 }, 577 { 578 Name: "select * with where, order by", 579 Query: "select * from people where `uuid` is not null and first_name <> 'Marge' order by last_name desc, age", 580 ExpectedRows: ToSqlRows(PeopleTestSchema, Moe, Lisa, Bart, Barney), 581 ExpectedSchema: CompressSchema(PeopleTestSchema), 582 }, 583 { 584 Name: "select subset of cols", 585 Query: "select first_name, last_name from people where age >= 40", 586 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer, Moe, Barney), 587 ExpectedSchema: CompressSchema(PeopleTestSchema, "first_name", "last_name"), 588 }, 589 { 590 Name: "column aliases", 591 Query: "select first_name as f, last_name as l from people where age >= 40", 592 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer, Moe, Barney), 593 ExpectedSchema: NewResultSetSchema("f", types.StringKind, "l", types.StringKind), 594 }, 595 { 596 Name: "duplicate column aliases", 597 Query: "select first_name as f, last_name as f from people where age >= 40", 598 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer, Moe, Barney), 599 ExpectedSchema: NewResultSetSchema("f", types.StringKind, "f", types.StringKind), 600 }, 601 { 602 Name: "column selected more than once", 603 Query: "select first_name, first_name from people where age >= 40 order by id", 604 ExpectedRows: []sql.Row{ 605 {"Homer", "Homer"}, 606 {"Moe", "Moe"}, 607 {"Barney", "Barney"}, 608 }, 609 ExpectedSchema: NewResultSetSchema("first_name", types.StringKind, "first_name", types.StringKind), 610 }, 611 { 612 Name: "duplicate table selection", 613 Query: "select first_name as f, last_name as f from people, people where age >= 40", 614 ExpectedErr: "Non-unique table name / alias: people", 615 }, 616 { 617 Name: "duplicate table alias", 618 Query: "select * from people p, people p where age >= 40", 619 ExpectedErr: "Non-unique table name / alias: 'p'", 620 }, 621 { 622 Name: "column aliases in where clause", 623 Query: `select first_name as f, last_name as l from people where f = "Homer"`, 624 ExpectedErr: "Unknown column: 'f'", 625 SkipOnSqlEngine: true, // this is actually a bug (aliases aren't usable in filters) 626 }, 627 { 628 Name: "select subset of columns with order by", 629 Query: "select first_name from people order by age, first_name", 630 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name"), Lisa, Bart, Marge, Barney, Homer, Moe), 631 ExpectedSchema: CompressSchema(PeopleTestSchema, "first_name"), 632 }, 633 { 634 Name: "column aliases with order by", 635 Query: "select first_name as f from people order by age, f", 636 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name"), Lisa, Bart, Marge, Barney, Homer, Moe), 637 ExpectedSchema: NewResultSetSchema("f", types.StringKind), 638 }, 639 { 640 Name: "ambiguous column in order by", 641 Query: "select first_name as f, last_name as f from people order by f", 642 ExpectedErr: "Ambiguous column: 'f'", 643 SkipOnSqlEngine: true, // this is a bug in go-mysql-server 644 }, 645 { 646 Name: "table aliases", 647 Query: "select p.first_name as f, p.last_name as l from people p where p.first_name = 'Homer'", 648 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer), 649 ExpectedSchema: NewResultSetSchema("f", types.StringKind, "l", types.StringKind), 650 }, 651 { 652 Name: "table aliases without column aliases", 653 Query: "select p.first_name, p.last_name from people p where p.first_name = 'Homer'", 654 ExpectedRows: ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer), 655 ExpectedSchema: NewResultSetSchema("first_name", types.StringKind, "last_name", types.StringKind), 656 }, 657 { 658 Name: "table aliases with bad alias", 659 Query: "select m.first_name as f, p.last_name as l from people p where p.f = 'Homer'", 660 ExpectedErr: "Unknown table: 'm'", 661 }, 662 { 663 Name: "column aliases, all columns", 664 Query: `select id as i, first_name as f, last_name as l, is_married as m, age as a, 665 rating as r, uuid as u, num_episodes as n from people 666 where age >= 40`, 667 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Moe, Barney), 668 ExpectedSchema: NewResultSetSchema("i", types.IntKind, "f", types.StringKind, 669 "l", types.StringKind, "m", types.IntKind, "a", types.IntKind, "r", types.FloatKind, 670 "u", types.StringKind, "n", types.UintKind), 671 }, 672 { 673 Name: "select *, not equals", 674 Query: "select * from people where age <> 40", 675 ExpectedRows: ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa, Moe), 676 ExpectedSchema: CompressSchema(PeopleTestSchema), 677 }, 678 { 679 Name: "empty result set", 680 Query: "select * from people where age > 80", 681 ExpectedRows: ToSqlRows(PeopleTestSchema), 682 ExpectedSchema: CompressSchema(PeopleTestSchema), 683 }, 684 { 685 Name: "empty result set with columns", 686 Query: "select id, age from people where age > 80", 687 ExpectedRows: ToSqlRows(PeopleTestSchema), 688 ExpectedSchema: CompressSchema(PeopleTestSchema, "id", "age"), 689 }, 690 { 691 Name: "unknown table", 692 Query: "select * from dne", 693 ExpectedErr: `Unknown table: 'dne'`, 694 }, 695 { 696 Name: "unknown diff table", 697 Query: "select * from dolt_diff_dne", 698 ExpectedErr: `Unknown table: 'dolt_diff_dne'`, 699 }, 700 { 701 Name: "unknown diff table", 702 Query: "select * from dolt_commit_diff_dne", 703 ExpectedErr: `Unknown table: 'dolt_commit_diff_dne'`, 704 }, 705 { 706 Name: "unknown history table", 707 Query: "select * from dolt_history_dne", 708 ExpectedErr: `Unknown table: 'dolt_history_dne'`, 709 }, 710 { 711 Name: "unknown table in join", 712 Query: "select * from people join dne", 713 ExpectedErr: `Unknown table: 'dne'`, 714 }, 715 { 716 Name: "no table", 717 Query: "select 1", 718 ExpectedSqlSchema: sql.Schema{ 719 &sql.Column{ 720 Name: "1", 721 Type: gmstypes.Int8, 722 }, 723 }, 724 ExpectedRows: []sql.Row{{int8(1)}}, 725 }, 726 { 727 Name: "unknown column in where", 728 Query: "select * from people where dne > 8.0", 729 ExpectedErr: `Unknown column: 'dne'`, 730 }, 731 { 732 Name: "unknown column in order by", 733 Query: "select * from people where rating > 8.0 order by dne", 734 ExpectedErr: `Unknown column: 'dne'`, 735 }, 736 { 737 Name: "unsupported comparison", 738 Query: "select * from people where function(first_name)", 739 ExpectedErr: "not supported", 740 }, 741 { 742 Name: "type mismatch in where clause", 743 Query: `select * from people where id = "0"`, 744 ExpectedSchema: CompressSchema(PeopleTestSchema), 745 ExpectedRows: ToSqlRows(PeopleTestSchema, Homer), 746 }, 747 { 748 Name: "select * from log system table", 749 Query: "select * from dolt_log", 750 ExpectedRows: []sql.Row{ 751 { 752 headCommitHash, 753 "billy bob", 754 "bigbillieb@fake.horse", 755 time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC).In(LoadedLocalLocation()), 756 "Initialize data repository", 757 }, 758 }, 759 ExpectedSqlSchema: sql.Schema{ 760 &sql.Column{Name: "commit_hash", Type: gmstypes.Text}, 761 &sql.Column{Name: "committer", Type: gmstypes.Text}, 762 &sql.Column{Name: "email", Type: gmstypes.Text}, 763 &sql.Column{Name: "date", Type: gmstypes.Datetime}, 764 &sql.Column{Name: "message", Type: gmstypes.Text}, 765 }, 766 }, 767 { 768 Name: "select * from conflicts system table", 769 Query: "select * from dolt_conflicts", 770 ExpectedRows: []sql.Row{}, 771 ExpectedSqlSchema: sql.Schema{ 772 &sql.Column{Name: "table", Type: gmstypes.Text}, 773 &sql.Column{Name: "num_conflicts", Type: gmstypes.Uint64}, 774 }, 775 }, 776 { 777 Name: "select * from branches system table", 778 Query: "select * from dolt_branches", 779 ExpectedRows: []sql.Row{ 780 { 781 env.DefaultInitBranch, 782 headCommitHash, 783 "billy bob", "bigbillieb@fake.horse", 784 time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC).In(LoadedLocalLocation()), 785 "Initialize data repository", 786 "", 787 "", 788 }, 789 }, 790 ExpectedSqlSchema: sql.Schema{ 791 &sql.Column{Name: "name", Type: gmstypes.Text}, 792 &sql.Column{Name: "hash", Type: gmstypes.Text}, 793 &sql.Column{Name: "latest_committer", Type: gmstypes.Text}, 794 &sql.Column{Name: "latest_committer_email", Type: gmstypes.Text}, 795 &sql.Column{Name: "latest_commit_date", Type: gmstypes.Datetime}, 796 &sql.Column{Name: "latest_commit_message", Type: gmstypes.Text}, 797 &sql.Column{Name: "remote", Type: gmstypes.Text}, 798 &sql.Column{Name: "branch", Type: gmstypes.Text}, 799 }, 800 }, 801 } 802 } 803 804 var sqlDiffSchema = sql.Schema{ 805 &sql.Column{Name: "to_id", Type: gmstypes.Int64}, 806 &sql.Column{Name: "to_first_name", Type: typeinfo.StringDefaultType.ToSqlType()}, 807 &sql.Column{Name: "to_last_name", Type: typeinfo.StringDefaultType.ToSqlType()}, 808 &sql.Column{Name: "to_addr", Type: typeinfo.StringDefaultType.ToSqlType()}, 809 &sql.Column{Name: "from_id", Type: gmstypes.Int64}, 810 &sql.Column{Name: "from_first_name", Type: typeinfo.StringDefaultType.ToSqlType()}, 811 &sql.Column{Name: "from_last_name", Type: typeinfo.StringDefaultType.ToSqlType()}, 812 &sql.Column{Name: "from_addr", Type: typeinfo.StringDefaultType.ToSqlType()}, 813 &sql.Column{Name: "diff_type", Type: typeinfo.StringDefaultType.ToSqlType()}, 814 } 815 816 var SelectDiffTests = []SelectTest{ 817 { 818 Name: "select from diff system table", 819 Query: "select to_id, to_first_name, to_last_name, to_addr, from_id, from_first_name, from_last_name, from_addr, diff_type from dolt_diff_test_table", 820 ExpectedRows: ToSqlRows(DiffSchema, 821 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(6), 1: types.String("Katie"), 2: types.String("McCulloch"), 14: types.String("added")})), 822 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 7: types.Int(0), 8: types.String("Aaron"), 9: types.String("Son"), 10: types.String("123 Fake St"), 14: types.String("modified")})), 823 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 7: types.Int(1), 8: types.String("Brian"), 9: types.String("Hendriks"), 10: types.String("456 Bull Ln"), 14: types.String("modified")})), 824 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 7: types.Int(2), 8: types.String("Tim"), 9: types.String("Sehn"), 10: types.String("789 Not Real Ct"), 14: types.String("modified")})), 825 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 7: types.Int(3), 8: types.String("Zach"), 9: types.String("Musgrave"), 14: types.String("modified")})), 826 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins"), 14: types.String("added")})), 827 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 14: types.String("added")})), 828 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 14: types.String("added")})), 829 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 14: types.String("added")})), 830 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 14: types.String("added")})), 831 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele"), 14: types.String("added")})), 832 ), 833 ExpectedSqlSchema: sqlDiffSchema, 834 }, 835 { 836 Name: "select from diff system table with to commit", 837 Query: "select to_id, to_first_name, to_last_name, to_addr, from_id, from_first_name, from_last_name, from_addr, diff_type from dolt_diff_test_table where to_commit = 'WORKING'", 838 ExpectedRows: ToSqlRows(DiffSchema, 839 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(6), 1: types.String("Katie"), 2: types.String("McCulloch"), 14: types.String("added")})), 840 ), 841 ExpectedSqlSchema: sqlDiffSchema, 842 }, 843 // TODO: fix dependencies to hashof function can be registered and used here, also create branches when generating the history so that different from and to commits can be tested. 844 /*{ 845 Name: "select from diff system table with from and to commit and test insensitive name", 846 Query: "select to_id, to_first_name, to_last_name, to_addr, to_age_4, to_age_5, from_id, from_first_name, from_last_name, from_addr, from_age_4, from_age_5, diff_type from dolt_diff_TeSt_TaBlE where from_commit = 'add-age' and to_commit = 'main'", 847 ExpectedRows: ToSqlRows(DiffSchema, 848 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(0), 8: types.String("Aaron"), 9: types.String("Son"), 11: types.Int(35), 0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35), 13: types.String("add-age"), 6: types.String("main"), 14: types.String("modified")})), 849 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(1), 8: types.String("Brian"), 9: types.String("Hendriks"), 11: types.Int(38), 0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38), 13: types.String("add-age"), 6: types.String("main"), 14: types.String("modified")})), 850 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(2), 8: types.String("Tim"), 9: types.String("Sehn"), 11: types.Int(37), 0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37), 13: types.String("add-age"), 6: types.String("main"), 14: types.String("modified")})), 851 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(3), 8: types.String("Zach"), 9: types.String("Musgrave"), 11: types.Int(37), 0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37), 13: types.String("add-age"), 6: types.String("main"), 14: types.String("modified")})), 852 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele"), 3: types.NullValue, 13: types.String("add-age"), 6: types.String("main"), 14: types.String("added")})), 853 mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins"), 3: types.NullValue, 13: types.String("add-age"), 6: types.String("main"), 14: types.String("added")})), 854 ), 855 ExpectedSqlSchema: sqlDiffSchema, 856 },*/ 857 } 858 859 var AsOfTests = []SelectTest{ 860 { 861 Name: "select * from seed branch", 862 Query: "select * from test_table as of 'seed'", 863 ExpectedRows: ToSqlRows(InitialHistSch, 864 mustRow(row.New(types.Format_Default, InitialHistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son")})), 865 mustRow(row.New(types.Format_Default, InitialHistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks")})), 866 mustRow(row.New(types.Format_Default, InitialHistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn")})), 867 ), 868 ExpectedSchema: InitialHistSch, 869 }, 870 { 871 Name: "select * from add-age branch", 872 Query: "select * from test_table as of 'add-age'", 873 ExpectedRows: ToSqlRows(AddAgeAt4HistSch, 874 mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 4: types.Int(35)})), 875 mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 4: types.Int(38)})), 876 mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 4: types.Int(37)})), 877 mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 4: types.Int(37)})), 878 ), 879 ExpectedSchema: AddAgeAt4HistSch, 880 }, 881 { 882 Name: "select * from main branch", 883 Query: "select * from test_table as of 'main'", 884 ExpectedRows: ToSqlRows(ReaddAgeAt5HistSch, 885 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)})), 886 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)})), 887 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)})), 888 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)})), 889 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 890 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")})), 891 ), 892 ExpectedSchema: ReaddAgeAt5HistSch, 893 }, 894 { 895 Name: "select * from HEAD~", 896 Query: "select * from test_table as of 'HEAD~'", 897 ExpectedRows: ToSqlRows(AddAddrAt3HistSch, 898 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})), 899 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})), 900 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})), 901 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})), 902 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 903 ), 904 ExpectedSchema: AddAddrAt3HistSch, 905 }, 906 { 907 Name: "select * from HEAD^", 908 Query: "select * from test_table as of 'HEAD^'", 909 ExpectedRows: ToSqlRows(AddAddrAt3HistSch, 910 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})), 911 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})), 912 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})), 913 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})), 914 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 915 ), 916 ExpectedSchema: AddAddrAt3HistSch, 917 }, 918 { 919 Name: "select * from main^", 920 Query: "select * from test_table as of 'main^'", 921 ExpectedRows: ToSqlRows(AddAddrAt3HistSch, 922 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})), 923 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})), 924 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})), 925 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})), 926 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 927 ), 928 ExpectedSchema: AddAddrAt3HistSch, 929 }, 930 // Because of an implementation detail in the way we process history for test setup, each commit is 2 hours apart. 931 { 932 Name: "select * from timestamp after HEAD", 933 Query: "select * from test_table as of CONVERT('1970-01-01 10:00:00', DATETIME)", 934 ExpectedRows: ToSqlRows(ReaddAgeAt5HistSch, 935 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)})), 936 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)})), 937 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)})), 938 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)})), 939 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 940 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")})), 941 ), 942 ExpectedSchema: ReaddAgeAt5HistSch, 943 }, 944 { 945 Name: "select * from timestamp, HEAD exact", 946 Query: "select * from test_table as of CONVERT('1970-01-01 08:00:00', DATETIME)", 947 ExpectedRows: ToSqlRows(ReaddAgeAt5HistSch, 948 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)})), 949 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)})), 950 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)})), 951 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)})), 952 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 953 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")})), 954 ), 955 ExpectedSchema: ReaddAgeAt5HistSch, 956 }, 957 { 958 Name: "select * from timestamp, HEAD~ + 1", 959 Query: "select * from test_table as of CONVERT('1970-01-01 07:00:00', DATETIME)", 960 ExpectedRows: ToSqlRows(AddAddrAt3HistSch, 961 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})), 962 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})), 963 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})), 964 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})), 965 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 966 ), 967 ExpectedSchema: AddAddrAt3HistSch, 968 }, 969 { 970 Name: "select * from timestamp, HEAD~", 971 Query: "select * from test_table as of CONVERT('1970-01-01 06:00:00', DATETIME)", 972 ExpectedRows: ToSqlRows(AddAddrAt3HistSch, 973 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})), 974 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})), 975 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})), 976 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})), 977 mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})), 978 ), 979 ExpectedSchema: AddAddrAt3HistSch, 980 }, 981 { 982 Name: "select * from timestamp, before table creation", 983 Query: "select * from test_table as of CONVERT('1970-01-01 02:00:00', DATETIME)", 984 ExpectedErr: "not found", 985 }, 986 { 987 Name: "select from dolt_docs as of main", 988 AdditionalSetup: CreateTableFn("dolt_docs", doltdb.DocsSchema, 989 "INSERT INTO dolt_docs VALUES ('LICENSE.md','A license')"), 990 Query: "select * from dolt_docs as of 'main'", 991 ExpectedRows: []sql.Row{{"LICENSE.md", "A license"}}, 992 ExpectedSchema: CompressSchema(doltdb.DocsSchema), 993 }, 994 } 995 996 // Tests of join functionality, basically any query involving more than one table should go here for now. 997 var JoinTests = []SelectTest{ 998 { 999 Name: "Full cross product", 1000 Query: `select * from people, episodes`, 1001 ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1002 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep1), 1003 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep2), 1004 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep3), 1005 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep4), 1006 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1), 1007 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep2), 1008 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep3), 1009 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep4), 1010 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep1), 1011 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2), 1012 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep3), 1013 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep4), 1014 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep1), 1015 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep2), 1016 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3), 1017 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep4), 1018 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep1), 1019 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep2), 1020 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep3), 1021 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep4), 1022 ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep1), 1023 ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep2), 1024 ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep3), 1025 ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep4), 1026 ), 1027 ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1028 }, 1029 { 1030 Name: "Natural join with where clause", 1031 Query: `select * from people p, episodes e where e.id = p.id`, 1032 ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1033 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1), 1034 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2), 1035 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3), 1036 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep4), 1037 ), 1038 ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1039 }, 1040 { 1041 Name: "Three table natural join with where clause", 1042 Query: `select p.*, e.* from people p, episodes e, appearances a where a.episode_id = e.id and a.character_id = p.id`, 1043 ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1044 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep1), 1045 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep2), 1046 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep3), 1047 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1), 1048 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep3), 1049 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2), 1050 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep2), 1051 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3), 1052 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep2), 1053 ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep3), 1054 ), 1055 ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1056 }, 1057 // TODO: error messages are different in SQL engine 1058 { 1059 Name: "ambiguous column in select", 1060 Query: `select id from people p, episodes e, appearances a where a.episode_id = e.id and a.character_id = p.id`, 1061 ExpectedErr: "Ambiguous column: 'id'", 1062 }, 1063 { 1064 Name: "ambiguous column in where", 1065 Query: `select p.*, e.* from people p, episodes e, appearances a where a.episode_id = id and a.character_id = id`, 1066 ExpectedErr: "Ambiguous column: 'id'", 1067 }, 1068 { 1069 Name: "Natural join with where clause, select subset of columns", 1070 Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p, episodes e where e.id = p.id`, 1071 ExpectedRows: ToSqlRows( 1072 NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1073 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1074 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1075 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1076 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1077 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1078 ), 1079 ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1080 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1081 }, 1082 { 1083 Name: "Natural join with where clause and column aliases", 1084 Query: "select e.id as eid, p.id as pid, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p, episodes e where e.id = p.id", 1085 ExpectedRows: ToSqlRows( 1086 NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1087 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1088 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1089 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1090 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1091 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1092 ), 1093 ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1094 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1095 }, 1096 { 1097 Name: "Natural join with where clause and quoted column alias", 1098 Query: "select e.id as eid, p.id as `p.id`, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p, episodes e where e.id = p.id", 1099 ExpectedRows: ToSqlRows( 1100 NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind, 1101 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1102 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1103 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1104 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1105 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1106 ), 1107 ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind, 1108 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1109 }, 1110 { 1111 Name: "Natural join with join clause", 1112 Query: `select * from people p join episodes e on e.id = p.id`, 1113 ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1114 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1), 1115 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2), 1116 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3), 1117 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep4), 1118 ), 1119 ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1120 }, 1121 { 1122 Name: "Three table natural join with join clause", 1123 Query: `select p.*, e.* from people p join appearances a on a.character_id = p.id join episodes e on a.episode_id = e.id`, 1124 ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1125 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep1), 1126 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep2), 1127 ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep3), 1128 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1), 1129 ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep3), 1130 ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2), 1131 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep2), 1132 ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3), 1133 ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep2), 1134 ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep3), 1135 ), 1136 ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema), 1137 }, 1138 { 1139 Name: "Natural join with join clause, select subset of columns", 1140 Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p join episodes e on e.id = p.id`, 1141 ExpectedRows: ToSqlRows( 1142 NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1143 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1144 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1145 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1146 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1147 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1148 ), 1149 ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1150 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1151 }, 1152 { 1153 Name: "Natural join with join clause, select subset of columns, join columns not selected", 1154 Query: `select e.name, p.first_name, p.last_name from people p join episodes e on e.id = p.id`, 1155 ExpectedRows: ToSqlRows(NewResultSetSchema("name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1156 NewResultSetRow(types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1157 NewResultSetRow(types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1158 NewResultSetRow(types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1159 NewResultSetRow(types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1160 ), 1161 ExpectedSchema: NewResultSetSchema("name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1162 }, 1163 { 1164 Name: "Natural join with join clause, select subset of columns, order by clause", 1165 Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p 1166 join episodes e on e.id = p.id 1167 order by e.name`, 1168 ExpectedRows: ToSqlRows( 1169 NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1170 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1171 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1172 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1173 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1174 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1175 ), 1176 ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1177 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1178 }, 1179 { 1180 Name: "Natural join with join clause, select subset of columns, order by clause on non-selected column", 1181 Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p 1182 join episodes e on e.id = p.id 1183 order by age`, 1184 ExpectedRows: ToSqlRows( 1185 NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1186 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1187 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1188 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1189 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1190 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1191 ), 1192 ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind, 1193 "name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind), 1194 }, 1195 { 1196 Name: "Natural join with join clause and column aliases", 1197 Query: "select e.id as eid, p.id as pid, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p join episodes e on e.id = p.id", 1198 ExpectedRows: ToSqlRows( 1199 NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1200 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1201 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1202 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1203 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1204 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1205 ), 1206 ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1207 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1208 }, 1209 { 1210 Name: "Natural join with join clause and column aliases, order by", 1211 Query: "select e.id as eid, p.id as pid, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p join episodes e on e.id = p.id order by ename", 1212 ExpectedRows: ToSqlRows( 1213 NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1214 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1215 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1216 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1217 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1218 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1219 ), 1220 ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1221 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1222 }, 1223 { 1224 Name: "Natural join with join clause and quoted column alias", 1225 Query: "select e.id as eid, p.id as `p.id`, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p join episodes e on e.id = p.id", 1226 ExpectedRows: ToSqlRows( 1227 NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind, 1228 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1229 NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")), 1230 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")), 1231 NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")), 1232 NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")), 1233 ), 1234 ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind, 1235 "ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind), 1236 }, 1237 { 1238 Name: "Join from table with two key columns to table with one key column", 1239 Query: `select a.episode_id as eid, p.id as pid, p.first_name 1240 from appearances a join people p on a.character_id = p.id order by eid, pid`, 1241 ExpectedRows: ToSqlRows( 1242 NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1243 "first_name", types.StringKind), 1244 NewResultSetRow(types.Int(1), types.Int(0), types.String("Homer")), 1245 NewResultSetRow(types.Int(1), types.Int(1), types.String("Marge")), 1246 NewResultSetRow(types.Int(2), types.Int(0), types.String("Homer")), 1247 NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart")), 1248 NewResultSetRow(types.Int(2), types.Int(3), types.String("Lisa")), 1249 NewResultSetRow(types.Int(2), types.Int(4), types.String("Moe")), 1250 NewResultSetRow(types.Int(3), types.Int(0), types.String("Homer")), 1251 NewResultSetRow(types.Int(3), types.Int(1), types.String("Marge")), 1252 NewResultSetRow(types.Int(3), types.Int(3), types.String("Lisa")), 1253 NewResultSetRow(types.Int(3), types.Int(5), types.String("Barney")), 1254 ), 1255 ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind, 1256 "first_name", types.StringKind), 1257 }, 1258 } 1259 1260 func TestSelect(t *testing.T) { 1261 for _, test := range BasicSelectTests() { 1262 t.Run(test.Name, func(t *testing.T) { 1263 testSelectQuery(t, test) 1264 }) 1265 } 1266 } 1267 1268 func TestAsOfQueries(t *testing.T) { 1269 if types.Format_Default != types.Format_LD_1 { 1270 t.Skip("") // todo: convert to enginetests 1271 } 1272 for _, test := range AsOfTests { 1273 t.Run(test.Name, func(t *testing.T) { 1274 // AS OF queries use the same history as the diff tests, so exercise the same test setup 1275 testSelectDiffQuery(t, test) 1276 }) 1277 } 1278 } 1279 1280 func TestJoins(t *testing.T) { 1281 for _, tt := range JoinTests { 1282 if tt.Name == "Join from table with two key columns to table with one key column" { 1283 t.Run(tt.Name, func(t *testing.T) { 1284 testSelectQuery(t, tt) 1285 }) 1286 } 1287 } 1288 } 1289 1290 var systemTableSelectTests = []SelectTest{ 1291 { 1292 Name: "select from dolt_docs", 1293 AdditionalSetup: CreateTableFn("dolt_docs", doltdb.DocsSchema, 1294 "INSERT INTO dolt_docs VALUES ('LICENSE.md','A license')"), 1295 Query: "select * from dolt_docs", 1296 ExpectedRows: []sql.Row{{"LICENSE.md", "A license"}}, 1297 ExpectedSchema: CompressSchema(doltdb.DocsSchema), 1298 }, 1299 { 1300 Name: "select from dolt_query_catalog", 1301 AdditionalSetup: CreateTableFn(doltdb.DoltQueryCatalogTableName, dtables.DoltQueryCatalogSchema, 1302 "INSERT INTO dolt_query_catalog VALUES ('existingEntry', 2, 'example', 'select 2+2 from dual', 'description')"), 1303 Query: "select * from dolt_query_catalog", 1304 ExpectedRows: ToSqlRows(CompressSchema(dtables.DoltQueryCatalogSchema), 1305 NewRow(types.String("existingEntry"), types.Uint(2), types.String("example"), types.String("select 2+2 from dual"), types.String("description")), 1306 ), 1307 ExpectedSchema: CompressSchema(dtables.DoltQueryCatalogSchema), 1308 }, 1309 { 1310 Name: "select from dolt_schemas", 1311 AdditionalSetup: CreateTableFn(doltdb.SchemasTableName, schemaTableSchema, 1312 `INSERT INTO dolt_schemas VALUES ('view', 'name', 'create view name as select 2+2 from dual', NULL, NULL)`), 1313 Query: "select * from dolt_schemas", 1314 ExpectedRows: []sql.Row{{"view", "name", "create view name as select 2+2 from dual", nil, nil}}, 1315 ExpectedSchema: CompressSchema(schemaTableSchema), 1316 }, 1317 } 1318 1319 func TestSelectSystemTables(t *testing.T) { 1320 for _, test := range systemTableSelectTests { 1321 t.Run(test.Name, func(t *testing.T) { 1322 testSelectQuery(t, test) 1323 }) 1324 } 1325 } 1326 1327 type testCommitClock struct { 1328 unixNano int64 1329 } 1330 1331 func (tcc *testCommitClock) Now() time.Time { 1332 now := time.Unix(0, tcc.unixNano) 1333 tcc.unixNano += int64(time.Hour) 1334 return now 1335 } 1336 1337 func installTestCommitClock() func() { 1338 oldNowFunc := datas.CommitterDate 1339 oldCommitLoc := datas.CommitLoc 1340 tcc := &testCommitClock{} 1341 datas.CommitterDate = tcc.Now 1342 datas.CommitLoc = time.UTC 1343 return func() { 1344 datas.CommitterDate = oldNowFunc 1345 datas.CommitLoc = oldCommitLoc 1346 } 1347 } 1348 1349 // Tests the given query on a freshly created dataset, asserting that the result has the given schema and rows. If 1350 // expectedErr is set, asserts instead that the execution returns an error that matches. 1351 func testSelectQuery(t *testing.T, test SelectTest) { 1352 validateTest(t, test) 1353 1354 cleanup := installTestCommitClock() 1355 defer cleanup() 1356 1357 dEnv, err := CreateTestDatabase() 1358 require.NoError(t, err) 1359 defer dEnv.DoltDB.Close() 1360 1361 if test.AdditionalSetup != nil { 1362 test.AdditionalSetup(t, dEnv) 1363 } 1364 1365 root, _ := dEnv.WorkingRoot(context.Background()) 1366 actualRows, sch, err := executeSelect(t, context.Background(), dEnv, root, test.Query) 1367 if len(test.ExpectedErr) > 0 { 1368 require.Error(t, err) 1369 // Too much work to synchronize error messages between the two implementations, so for now we'll just assert that an error occurred. 1370 // require.Contains(t, err.Error(), test.ExpectedErr) 1371 return 1372 } else { 1373 require.NoError(t, err) 1374 } 1375 1376 // JSON columns must be compared using like so 1377 assert.Equal(t, len(test.ExpectedRows), len(actualRows)) 1378 for i := 0; i < len(test.ExpectedRows); i++ { 1379 assert.Equal(t, len(test.ExpectedRows[i]), len(actualRows[i])) 1380 for j := 0; j < len(test.ExpectedRows[i]); j++ { 1381 if _, ok := actualRows[i][j].(json.NomsJSON); ok { 1382 cmp, err := gmstypes.CompareJSON(actualRows[i][j].(json.NomsJSON), test.ExpectedRows[i][j].(json.NomsJSON)) 1383 assert.NoError(t, err) 1384 assert.Equal(t, 0, cmp) 1385 } else { 1386 assert.Equal(t, test.ExpectedRows[i][j], actualRows[i][j]) 1387 } 1388 1389 } 1390 } 1391 1392 var sqlSchema sql.Schema 1393 if test.ExpectedSqlSchema != nil { 1394 sqlSchema = test.ExpectedSqlSchema 1395 } else { 1396 sqlSchema = mustSqlSchema(test.ExpectedSchema) 1397 } 1398 1399 assertSchemasEqual(t, sqlSchema, sch) 1400 } 1401 1402 const TableWithHistoryName = "test_table" 1403 1404 var InitialHistSch = dtestutils.MustSchema(idColTag0TypeUUID, firstColTag1TypeStr, lastColTag2TypeStr) 1405 var AddAddrAt3HistSch = dtestutils.MustSchema(idColTag0TypeUUID, firstColTag1TypeStr, lastColTag2TypeStr, addrColTag3TypeStr) 1406 var AddAgeAt4HistSch = dtestutils.MustSchema(idColTag0TypeUUID, firstColTag1TypeStr, lastColTag2TypeStr, ageColTag4TypeInt) 1407 var ReaddAgeAt5HistSch = dtestutils.MustSchema(idColTag0TypeUUID, firstColTag1TypeStr, lastColTag2TypeStr, addrColTag3TypeStr, ageColTag5TypeUint) 1408 1409 // TableUpdate defines a list of modifications that should be made to a table 1410 type TableUpdate struct { 1411 // NewSch is an updated schema for this table. It overwrites the existing value. If not provided the existing value 1412 // will not change 1413 NewSch schema.Schema 1414 1415 // NewRowData if provided overwrites the entirety of the row data in the table. 1416 NewRowData *types.Map 1417 1418 // RowUpdates are new values for rows that should be set in the map. They can be updates or inserts. 1419 RowUpdates []row.Row 1420 } 1421 1422 // HistoryNode represents a commit to be made 1423 type HistoryNode struct { 1424 // Branch the branch that the commit should be on 1425 Branch string 1426 1427 // CommitMessag is the commit message that should be applied 1428 CommitMsg string 1429 1430 // Updates are the changes that should be made to the table's states before committing 1431 Updates map[string]TableUpdate 1432 1433 // Children are the child commits of this commit 1434 Children []HistoryNode 1435 } 1436 1437 // mustRowData converts a slice of row.TaggedValues into a noms types.Map containing that data. 1438 func mustRowData(t *testing.T, ctx context.Context, vrw types.ValueReadWriter, sch schema.Schema, colVals []row.TaggedValues) *types.Map { 1439 m, err := types.NewMap(ctx, vrw) 1440 require.NoError(t, err) 1441 1442 me := m.Edit() 1443 for _, taggedVals := range colVals { 1444 r, err := row.New(types.Format_Default, sch, taggedVals) 1445 require.NoError(t, err) 1446 1447 me = me.Set(r.NomsMapKey(sch), r.NomsMapValue(sch)) 1448 } 1449 1450 m, err = me.Map(ctx) 1451 require.NoError(t, err) 1452 1453 return &m 1454 } 1455 1456 func CreateHistory(ctx context.Context, dEnv *env.DoltEnv, t *testing.T) []HistoryNode { 1457 vrw := dEnv.DoltDB.ValueReadWriter() 1458 1459 return []HistoryNode{ 1460 { 1461 Branch: "seed", 1462 CommitMsg: "Seeding with initial user data", 1463 Updates: map[string]TableUpdate{ 1464 TableWithHistoryName: { 1465 NewSch: InitialHistSch, 1466 NewRowData: mustRowData(t, ctx, vrw, InitialHistSch, []row.TaggedValues{ 1467 {0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son")}, 1468 {0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks")}, 1469 {0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn")}, 1470 }), 1471 }, 1472 }, 1473 Children: []HistoryNode{ 1474 { 1475 Branch: "add-age", 1476 CommitMsg: "Adding int age to users with tag 3", 1477 Updates: map[string]TableUpdate{ 1478 TableWithHistoryName: { 1479 NewSch: AddAgeAt4HistSch, 1480 NewRowData: mustRowData(t, ctx, vrw, AddAgeAt4HistSch, []row.TaggedValues{ 1481 {0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 4: types.Int(35)}, 1482 {0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 4: types.Int(38)}, 1483 {0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 4: types.Int(37)}, 1484 {0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 4: types.Int(37)}, 1485 }), 1486 }, 1487 }, 1488 Children: nil, 1489 }, 1490 { 1491 Branch: env.DefaultInitBranch, 1492 CommitMsg: "Adding string address to users with tag 3", 1493 Updates: map[string]TableUpdate{ 1494 TableWithHistoryName: { 1495 NewSch: AddAddrAt3HistSch, 1496 NewRowData: mustRowData(t, ctx, vrw, AddAddrAt3HistSch, []row.TaggedValues{ 1497 {0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")}, 1498 {0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")}, 1499 {0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")}, 1500 {0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")}, 1501 {0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")}, 1502 }), 1503 }, 1504 }, 1505 Children: []HistoryNode{ 1506 { 1507 Branch: env.DefaultInitBranch, 1508 CommitMsg: "Re-add age as a uint with tag 4", 1509 Updates: map[string]TableUpdate{ 1510 TableWithHistoryName: { 1511 NewSch: ReaddAgeAt5HistSch, 1512 NewRowData: mustRowData(t, ctx, vrw, ReaddAgeAt5HistSch, []row.TaggedValues{ 1513 {0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)}, 1514 {0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)}, 1515 {0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)}, 1516 {0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)}, 1517 {0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")}, 1518 {0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")}, 1519 }), 1520 }, 1521 }, 1522 Children: nil, 1523 }, 1524 }, 1525 }, 1526 }, 1527 }, 1528 } 1529 } 1530 1531 var idColTag0TypeUUID = schema.NewColumn("id", 0, types.IntKind, true) 1532 var firstColTag1TypeStr = schema.NewColumn("first_name", 1, types.StringKind, false) 1533 var lastColTag2TypeStr = schema.NewColumn("last_name", 2, types.StringKind, false) 1534 var addrColTag3TypeStr = schema.NewColumn("addr", 3, types.StringKind, false) 1535 var ageColTag4TypeInt = schema.NewColumn("age", 4, types.IntKind, false) 1536 var ageColTag5TypeUint = schema.NewColumn("age", 5, types.UintKind, false) 1537 1538 var DiffSchema = dtestutils.MustSchema( 1539 schema.NewColumn("to_id", 0, types.IntKind, false), 1540 schema.NewColumn("to_first_name", 1, types.StringKind, false), 1541 schema.NewColumn("to_last_name", 2, types.StringKind, false), 1542 schema.NewColumn("to_addr", 3, types.StringKind, false), 1543 schema.NewColumn("from_id", 7, types.IntKind, false), 1544 schema.NewColumn("from_first_name", 8, types.StringKind, false), 1545 schema.NewColumn("from_last_name", 9, types.StringKind, false), 1546 schema.NewColumn("from_addr", 10, types.StringKind, false), 1547 schema.NewColumn("diff_type", 14, types.StringKind, false), 1548 ) 1549 1550 func testSelectDiffQuery(t *testing.T, test SelectTest) { 1551 validateTest(t, test) 1552 ctx := context.Background() 1553 cleanup := installTestCommitClock() 1554 defer cleanup() 1555 dEnv := dtestutils.CreateTestEnv() 1556 initializeWithHistory(t, ctx, dEnv, CreateHistory(ctx, dEnv, t)...) 1557 if test.AdditionalSetup != nil { 1558 test.AdditionalSetup(t, dEnv) 1559 } 1560 1561 cs, err := doltdb.NewCommitSpec("main") 1562 require.NoError(t, err) 1563 1564 optCmt, err := dEnv.DoltDB.Resolve(ctx, cs, nil) 1565 require.NoError(t, err) 1566 1567 cm, ok := optCmt.ToCommit() 1568 require.True(t, ok) 1569 1570 root, err := cm.GetRootValue(ctx) 1571 require.NoError(t, err) 1572 1573 err = dEnv.UpdateStagedRoot(ctx, root) 1574 require.NoError(t, err) 1575 1576 err = dEnv.UpdateWorkingRoot(ctx, root) 1577 require.NoError(t, err) 1578 1579 root, err = dEnv.WorkingRoot(context.Background()) 1580 require.NoError(t, err) 1581 1582 root = updateTables(t, ctx, root, createWorkingRootUpdate()) 1583 1584 err = dEnv.UpdateWorkingRoot(ctx, root) 1585 require.NoError(t, err) 1586 1587 actualRows, sch, err := executeSelect(t, ctx, dEnv, root, test.Query) 1588 if len(test.ExpectedErr) > 0 { 1589 require.Error(t, err) 1590 return 1591 } else { 1592 require.NoError(t, err) 1593 } 1594 1595 assert.Equal(t, test.ExpectedRows, actualRows) 1596 1597 var sqlSchema sql.Schema 1598 if test.ExpectedSqlSchema != nil { 1599 sqlSchema = test.ExpectedSqlSchema 1600 } else { 1601 sqlSchema = mustSqlSchema(test.ExpectedSchema) 1602 } 1603 1604 assertSchemasEqual(t, sqlSchema, sch) 1605 } 1606 1607 // TODO: this shouldn't be here 1608 func createWorkingRootUpdate() map[string]TableUpdate { 1609 return map[string]TableUpdate{ 1610 TableWithHistoryName: { 1611 RowUpdates: []row.Row{ 1612 mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{ 1613 0: types.Int(6), 1: types.String("Katie"), 2: types.String("McCulloch"), 1614 })), 1615 }, 1616 }, 1617 } 1618 } 1619 1620 func updateTables(t *testing.T, ctx context.Context, root doltdb.RootValue, tblUpdates map[string]TableUpdate) doltdb.RootValue { 1621 for tblName, updates := range tblUpdates { 1622 tbl, ok, err := root.GetTable(ctx, doltdb.TableName{Name: tblName}) 1623 require.NoError(t, err) 1624 1625 var sch schema.Schema 1626 if updates.NewSch != nil { 1627 sch = updates.NewSch 1628 } else { 1629 sch, err = tbl.GetSchema(ctx) 1630 require.NoError(t, err) 1631 } 1632 1633 var rowData types.Map 1634 if updates.NewRowData == nil { 1635 if ok { 1636 rowData, err = tbl.GetNomsRowData(ctx) 1637 require.NoError(t, err) 1638 } else { 1639 rowData, err = types.NewMap(ctx, root.VRW()) 1640 require.NoError(t, err) 1641 } 1642 } else { 1643 rowData = *updates.NewRowData 1644 } 1645 1646 if updates.RowUpdates != nil { 1647 me := rowData.Edit() 1648 1649 for _, r := range updates.RowUpdates { 1650 me = me.Set(r.NomsMapKey(sch), r.NomsMapValue(sch)) 1651 } 1652 1653 rowData, err = me.Map(ctx) 1654 require.NoError(t, err) 1655 } 1656 1657 var indexData durable.IndexSet 1658 require.NoError(t, err) 1659 if tbl != nil { 1660 indexData, err = tbl.GetIndexSet(ctx) 1661 require.NoError(t, err) 1662 } 1663 1664 tbl, err = doltdb.NewNomsTable(ctx, root.VRW(), root.NodeStore(), sch, rowData, indexData, nil) 1665 require.NoError(t, err) 1666 1667 root, err = root.PutTable(ctx, doltdb.TableName{Name: tblName}, tbl) 1668 require.NoError(t, err) 1669 } 1670 1671 return root 1672 } 1673 1674 // initializeWithHistory will go through the provided historyNodes and create the intended commit graph 1675 func initializeWithHistory(t *testing.T, ctx context.Context, dEnv *env.DoltEnv, historyNodes ...HistoryNode) { 1676 for _, node := range historyNodes { 1677 cs, err := doltdb.NewCommitSpec(env.DefaultInitBranch) 1678 require.NoError(t, err) 1679 1680 optCmt, err := dEnv.DoltDB.Resolve(ctx, cs, nil) 1681 require.NoError(t, err) 1682 1683 cm, ok := optCmt.ToCommit() 1684 require.True(t, ok) 1685 1686 processNode(t, ctx, dEnv, node, cm) 1687 } 1688 } 1689 1690 func processNode(t *testing.T, ctx context.Context, dEnv *env.DoltEnv, node HistoryNode, parent *doltdb.Commit) { 1691 branchRef := ref.NewBranchRef(node.Branch) 1692 ok, err := dEnv.DoltDB.HasRef(ctx, branchRef) 1693 require.NoError(t, err) 1694 1695 if !ok { 1696 err = dEnv.DoltDB.NewBranchAtCommit(ctx, branchRef, parent, nil) 1697 require.NoError(t, err) 1698 } 1699 1700 cs, err := doltdb.NewCommitSpec(branchRef.String()) 1701 require.NoError(t, err) 1702 1703 optCmt, err := dEnv.DoltDB.Resolve(ctx, cs, nil) 1704 require.NoError(t, err) 1705 1706 cm, ok := optCmt.ToCommit() 1707 require.True(t, ok) 1708 1709 root, err := cm.GetRootValue(ctx) 1710 require.NoError(t, err) 1711 1712 root = updateTables(t, ctx, root, node.Updates) 1713 r, h, err := dEnv.DoltDB.WriteRootValue(ctx, root) 1714 require.NoError(t, err) 1715 root = r 1716 1717 meta, err := datas.NewCommitMeta("Ash Ketchum", "ash@poke.mon", node.CommitMsg) 1718 require.NoError(t, err) 1719 1720 cm, err = dEnv.DoltDB.Commit(ctx, h, branchRef, meta) 1721 require.NoError(t, err) 1722 1723 for _, child := range node.Children { 1724 processNode(t, ctx, dEnv, child, cm) 1725 } 1726 } 1727 1728 func validateTest(t *testing.T, test SelectTest) { 1729 if (test.ExpectedRows == nil) != (test.ExpectedSchema == nil && test.ExpectedSqlSchema == nil) { 1730 require.Fail(t, "Incorrect test setup: schema and rows must both be provided if one is") 1731 } 1732 1733 if len(test.ExpectedErr) == 0 && (test.ExpectedSchema == nil) == (test.ExpectedSqlSchema == nil) { 1734 require.Fail(t, "Incorrect test setup: must set at most one of ExpectedSchema, ExpectedSqlSchema") 1735 } 1736 1737 if len(singleSelectQueryTest) > 0 && test.Name != singleSelectQueryTest { 1738 t.Skip("Skipping tests until " + singleSelectQueryTest) 1739 } 1740 1741 if len(singleSelectQueryTest) == 0 && test.SkipOnSqlEngine && skipBrokenSelect { 1742 t.Skip("Skipping test broken on SQL engine") 1743 } 1744 }