1/* 2Copyright 2019 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package spannertest 18 19// This file contains the part of the Spanner fake that evaluates expressions. 20 21import ( 22 "bytes" 23 "fmt" 24 "regexp" 25 "strconv" 26 "strings" 27 "time" 28 29 "cloud.google.com/go/civil" 30 "cloud.google.com/go/spanner/spansql" 31 "google.golang.org/grpc/codes" 32 "google.golang.org/grpc/status" 33) 34 35// evalContext represents the context for evaluating an expression. 36type evalContext struct { 37 // cols and row are set during expr evaluation. 38 cols []colInfo 39 row row 40 41 // If there are visible aliases, they are populated here. 42 aliases map[spansql.ID]spansql.Expr 43 44 params queryParams 45} 46 47// coercedValue represents a literal value that has been coerced to a different type. 48// This never leaves this package, nor is persisted. 49type coercedValue struct { 50 spansql.Expr // not a real Expr 51 val interface{} // internal representation 52 // TODO: type? 53 orig spansql.Expr 54} 55 56func (cv coercedValue) SQL() string { return cv.orig.SQL() } 57 58func (ec evalContext) evalExprList(list []spansql.Expr) ([]interface{}, error) { 59 var out []interface{} 60 for _, e := range list { 61 x, err := ec.evalExpr(e) 62 if err != nil { 63 return nil, err 64 } 65 out = append(out, x) 66 } 67 return out, nil 68} 69 70func (ec evalContext) evalBoolExpr(be spansql.BoolExpr) (*bool, error) { 71 switch be := be.(type) { 72 default: 73 return nil, fmt.Errorf("unhandled BoolExpr %T", be) 74 case spansql.BoolLiteral: 75 b := bool(be) 76 return &b, nil 77 case spansql.ID, spansql.Param, spansql.Paren, spansql.Func, spansql.InOp: // InOp is a bit weird. 78 e, err := ec.evalExpr(be) 79 if err != nil { 80 return nil, err 81 } 82 if e == nil { 83 return nil, nil // preserve NULLs 84 } 85 b, ok := e.(bool) 86 if !ok { 87 return nil, fmt.Errorf("got %T, want bool", e) 88 } 89 return &b, nil 90 case spansql.LogicalOp: 91 var lhs, rhs *bool 92 var err error 93 if be.LHS != nil { 94 lhs, err = ec.evalBoolExpr(be.LHS) 95 if err != nil { 96 return nil, err 97 } 98 } 99 rhs, err = ec.evalBoolExpr(be.RHS) 100 if err != nil { 101 return nil, err 102 } 103 // https://cloud.google.com/spanner/docs/operators#logical_operators 104 switch be.Op { 105 case spansql.And: 106 if lhs != nil { 107 if *lhs { 108 // TRUE AND x => x 109 return rhs, nil 110 } 111 // FALSE AND x => FALSE 112 return lhs, nil 113 } 114 // NULL AND FALSE => FALSE 115 if rhs != nil && !*rhs { 116 return rhs, nil 117 } 118 // NULL AND TRUE|NULL => NULL 119 return nil, nil 120 case spansql.Or: 121 if lhs != nil { 122 if *lhs { 123 // TRUE OR x => TRUE 124 return lhs, nil 125 } 126 // FALSE OR x => x 127 return rhs, nil 128 } 129 // NULL OR TRUE => TRUE 130 if rhs != nil && *rhs { 131 return rhs, nil 132 } 133 // NULL OR FALSE|NULL => NULL 134 return nil, nil 135 case spansql.Not: 136 if rhs == nil { 137 return nil, nil 138 } 139 b := !*rhs 140 return &b, nil 141 default: 142 return nil, fmt.Errorf("unhandled LogicalOp %d", be.Op) 143 } 144 case spansql.ComparisonOp: 145 // Per https://cloud.google.com/spanner/docs/operators#comparison_operators, 146 // "Cloud Spanner SQL will generally coerce literals to the type of non-literals, where present". 147 // Before evaluating be.LHS and be.RHS, do any necessary coercion. 148 be, err := ec.coerceComparisonOpArgs(be) 149 if err != nil { 150 return nil, err 151 } 152 153 lhs, err := ec.evalExpr(be.LHS) 154 if err != nil { 155 return nil, err 156 } 157 rhs, err := ec.evalExpr(be.RHS) 158 if err != nil { 159 return nil, err 160 } 161 if lhs == nil || rhs == nil { 162 // https://cloud.google.com/spanner/docs/operators#comparison_operators says 163 // "any operation with a NULL input returns NULL." 164 return nil, nil 165 } 166 var b bool 167 switch be.Op { 168 default: 169 return nil, fmt.Errorf("TODO: ComparisonOp %d", be.Op) 170 case spansql.Lt: 171 b = compareVals(lhs, rhs) < 0 172 case spansql.Le: 173 b = compareVals(lhs, rhs) <= 0 174 case spansql.Gt: 175 b = compareVals(lhs, rhs) > 0 176 case spansql.Ge: 177 b = compareVals(lhs, rhs) >= 0 178 case spansql.Eq: 179 b = compareVals(lhs, rhs) == 0 180 case spansql.Ne: 181 b = compareVals(lhs, rhs) != 0 182 case spansql.Like, spansql.NotLike: 183 left, ok := lhs.(string) 184 if !ok { 185 // TODO: byte works here too? 186 return nil, fmt.Errorf("LHS of LIKE is %T, not string", lhs) 187 } 188 right, ok := rhs.(string) 189 if !ok { 190 // TODO: byte works here too? 191 return nil, fmt.Errorf("RHS of LIKE is %T, not string", rhs) 192 } 193 194 b = evalLike(left, right) 195 if be.Op == spansql.NotLike { 196 b = !b 197 } 198 case spansql.Between, spansql.NotBetween: 199 rhs2, err := ec.evalExpr(be.RHS2) 200 if err != nil { 201 return nil, err 202 } 203 b = compareVals(rhs, lhs) <= 0 && compareVals(lhs, rhs2) <= 0 204 if be.Op == spansql.NotBetween { 205 b = !b 206 } 207 } 208 return &b, nil 209 case spansql.IsOp: 210 lhs, err := ec.evalExpr(be.LHS) 211 if err != nil { 212 return nil, err 213 } 214 var b bool 215 switch rhs := be.RHS.(type) { 216 default: 217 return nil, fmt.Errorf("unhandled IsOp %T", rhs) 218 case spansql.BoolLiteral: 219 if lhs == nil { 220 // For `X IS TRUE`, X being NULL is okay, and this evaluates 221 // to false. Same goes for `X IS FALSE`. 222 lhs = !bool(rhs) 223 } 224 lhsBool, ok := lhs.(bool) 225 if !ok { 226 return nil, fmt.Errorf("non-bool value %T on LHS for %s", lhs, be.SQL()) 227 } 228 b = (lhsBool == bool(rhs)) 229 case spansql.NullLiteral: 230 b = (lhs == nil) 231 } 232 if be.Neg { 233 b = !b 234 } 235 return &b, nil 236 } 237} 238 239func (ec evalContext) evalArithOp(e spansql.ArithOp) (interface{}, error) { 240 switch e.Op { 241 case spansql.Neg: 242 rhs, err := ec.evalExpr(e.RHS) 243 if err != nil { 244 return nil, err 245 } 246 switch rhs := rhs.(type) { 247 case float64: 248 return -rhs, nil 249 case int64: 250 return -rhs, nil 251 } 252 return nil, fmt.Errorf("RHS of %s evaluates to %T, want FLOAT64 or INT64", e.SQL(), rhs) 253 case spansql.BitNot: 254 rhs, err := ec.evalExpr(e.RHS) 255 if err != nil { 256 return nil, err 257 } 258 switch rhs := rhs.(type) { 259 case int64: 260 return ^rhs, nil 261 case []byte: 262 b := append([]byte(nil), rhs...) // deep copy 263 for i := range b { 264 b[i] = ^b[i] 265 } 266 return b, nil 267 } 268 return nil, fmt.Errorf("RHS of %s evaluates to %T, want INT64 or BYTES", e.SQL(), rhs) 269 case spansql.Div: 270 lhs, err := ec.evalFloat64(e.LHS) 271 if err != nil { 272 return nil, err 273 } 274 rhs, err := ec.evalFloat64(e.RHS) 275 if err != nil { 276 return nil, err 277 } 278 if rhs == 0 { 279 // TODO: Does real Spanner use a specific error code here? 280 return nil, fmt.Errorf("divide by zero") 281 } 282 return lhs / rhs, nil 283 case spansql.Add, spansql.Sub, spansql.Mul: 284 lhs, err := ec.evalExpr(e.LHS) 285 if err != nil { 286 return nil, err 287 } 288 rhs, err := ec.evalExpr(e.RHS) 289 if err != nil { 290 return nil, err 291 } 292 i1, ok1 := lhs.(int64) 293 i2, ok2 := rhs.(int64) 294 if ok1 && ok2 { 295 switch e.Op { 296 case spansql.Add: 297 return i1 + i2, nil 298 case spansql.Sub: 299 return i1 - i2, nil 300 case spansql.Mul: 301 return i1 * i2, nil 302 } 303 } 304 f1, err := asFloat64(e.LHS, lhs) 305 if err != nil { 306 return nil, err 307 } 308 f2, err := asFloat64(e.RHS, rhs) 309 if err != nil { 310 return nil, err 311 } 312 switch e.Op { 313 case spansql.Add: 314 return f1 + f2, nil 315 case spansql.Sub: 316 return f1 - f2, nil 317 case spansql.Mul: 318 return f1 * f2, nil 319 } 320 case spansql.BitAnd, spansql.BitXor, spansql.BitOr: 321 lhs, err := ec.evalExpr(e.LHS) 322 if err != nil { 323 return nil, err 324 } 325 rhs, err := ec.evalExpr(e.RHS) 326 if err != nil { 327 return nil, err 328 } 329 i1, ok1 := lhs.(int64) 330 i2, ok2 := rhs.(int64) 331 if ok1 && ok2 { 332 switch e.Op { 333 case spansql.BitAnd: 334 return i1 & i2, nil 335 case spansql.BitXor: 336 return i1 ^ i2, nil 337 case spansql.BitOr: 338 return i1 | i2, nil 339 } 340 } 341 b1, ok1 := lhs.([]byte) 342 b2, ok2 := rhs.([]byte) 343 if !ok1 || !ok2 { 344 return nil, fmt.Errorf("arguments of %s evaluate to (%T, %T), want (INT64, INT64) or (BYTES, BYTES)", e.SQL(), lhs, rhs) 345 } 346 if len(b1) != len(b2) { 347 return nil, fmt.Errorf("arguments of %s evaluate to BYTES of unequal lengths (%d vs %d)", e.SQL(), len(b1), len(b2)) 348 } 349 var f func(x, y byte) byte 350 switch e.Op { 351 case spansql.BitAnd: 352 f = func(x, y byte) byte { return x & y } 353 case spansql.BitXor: 354 f = func(x, y byte) byte { return x ^ y } 355 case spansql.BitOr: 356 f = func(x, y byte) byte { return x | y } 357 } 358 b := make([]byte, len(b1)) 359 for i := range b1 { 360 b[i] = f(b1[i], b2[i]) 361 } 362 return b, nil 363 } 364 // TODO: Concat, BitShl, BitShr 365 return nil, fmt.Errorf("TODO: evalArithOp(%s %v)", e.SQL(), e.Op) 366} 367 368func (ec evalContext) evalFunc(e spansql.Func) (interface{}, spansql.Type, error) { 369 if f, ok := functions[e.Name]; ok { 370 args := make([]interface{}, len(e.Args)) 371 for i, arg := range e.Args { 372 val, err := ec.evalExpr(arg) 373 if err != nil { 374 return nil, spansql.Type{}, err 375 } 376 args[i] = val 377 } 378 return f.Eval(args) 379 } 380 return nil, spansql.Type{}, status.Errorf(codes.Unimplemented, "function %q is not implemented", e.Name) 381} 382 383// evalFloat64 evaluates an expression and returns its FLOAT64 value. 384// If the expression does not yield a FLOAT64 or INT64 it returns an error. 385func (ec evalContext) evalFloat64(e spansql.Expr) (float64, error) { 386 v, err := ec.evalExpr(e) 387 if err != nil { 388 return 0, err 389 } 390 return asFloat64(e, v) 391} 392 393func asFloat64(e spansql.Expr, v interface{}) (float64, error) { 394 switch v := v.(type) { 395 default: 396 return 0, fmt.Errorf("expression %s evaluates to %T, want FLOAT64 or INT64", e.SQL(), v) 397 case float64: 398 return v, nil 399 case int64: 400 return float64(v), nil 401 } 402} 403 404func (ec evalContext) evalExpr(e spansql.Expr) (interface{}, error) { 405 // Several cases below are handled by this. 406 // It evaluates a BoolExpr (which returns *bool for a tri-state BOOL) 407 // and converts it to true/false/nil. 408 evalBool := func(be spansql.BoolExpr) (interface{}, error) { 409 b, err := ec.evalBoolExpr(be) 410 if err != nil { 411 return nil, err 412 } 413 if b == nil { 414 return nil, nil // (*bool)(nil) -> interface nil 415 } 416 return *b, nil 417 } 418 419 switch e := e.(type) { 420 default: 421 return nil, fmt.Errorf("TODO: evalExpr(%s %T)", e.SQL(), e) 422 case coercedValue: 423 return e.val, nil 424 case spansql.PathExp: 425 return ec.evalPathExp(e) 426 case spansql.ID: 427 return ec.evalID(e) 428 case spansql.Param: 429 qp, ok := ec.params[string(e)] 430 if !ok { 431 return 0, fmt.Errorf("unbound param %s", e.SQL()) 432 } 433 return qp.Value, nil 434 case spansql.IntegerLiteral: 435 return int64(e), nil 436 case spansql.FloatLiteral: 437 return float64(e), nil 438 case spansql.StringLiteral: 439 return string(e), nil 440 case spansql.BytesLiteral: 441 return []byte(e), nil 442 case spansql.NullLiteral: 443 return nil, nil 444 case spansql.BoolLiteral: 445 return bool(e), nil 446 case spansql.Paren: 447 return ec.evalExpr(e.Expr) 448 case spansql.Func: 449 v, _, err := ec.evalFunc(e) 450 if err != nil { 451 return nil, err 452 } 453 return v, nil 454 case spansql.Array: 455 var arr []interface{} 456 for _, elt := range e { 457 v, err := ec.evalExpr(elt) 458 if err != nil { 459 return nil, err 460 } 461 arr = append(arr, v) 462 } 463 // TODO: enforce or coerce to consistent types. 464 return arr, nil 465 case spansql.ArithOp: 466 return ec.evalArithOp(e) 467 case spansql.LogicalOp: 468 return evalBool(e) 469 case spansql.ComparisonOp: 470 return evalBool(e) 471 case spansql.InOp: 472 // This is implemented here in evalExpr instead of evalBoolExpr 473 // because it can return FALSE/TRUE/NULL. 474 // The docs are a bit confusing here, so there's probably some bugs here around NULL handling. 475 // TODO: Can this now simplify using evalBool? 476 477 if len(e.RHS) == 0 { 478 // "IN with an empty right side expression is always FALSE". 479 return e.Neg, nil 480 } 481 lhs, err := ec.evalExpr(e.LHS) 482 if err != nil { 483 return false, err 484 } 485 if lhs == nil { 486 // "IN with a NULL left side expression and a non-empty right side expression is always NULL". 487 return nil, nil 488 } 489 var b bool 490 for _, rhse := range e.RHS { 491 rhs, err := ec.evalExpr(rhse) 492 if err != nil { 493 return false, err 494 } 495 if !e.Unnest { 496 if lhs == rhs { 497 b = true 498 } 499 } else { 500 if rhs == nil { 501 // "IN UNNEST(<NULL array>) returns FALSE (not NULL)". 502 return e.Neg, nil 503 } 504 arr, ok := rhs.([]interface{}) 505 if !ok { 506 return nil, fmt.Errorf("UNNEST argument evaluated as %T, want array", rhs) 507 } 508 for _, rhs := range arr { 509 // == isn't okay here. 510 if compareVals(lhs, rhs) == 0 { 511 b = true 512 } 513 } 514 } 515 } 516 if e.Neg { 517 b = !b 518 } 519 return b, nil 520 case spansql.IsOp: 521 return evalBool(e) 522 case aggSentinel: 523 // Match up e.AggIndex with the column. 524 // They might have been reordered. 525 ci := -1 526 for i, col := range ec.cols { 527 if col.AggIndex == e.AggIndex { 528 ci = i 529 break 530 } 531 } 532 if ci < 0 { 533 return 0, fmt.Errorf("internal error: did not find aggregate column %d", e.AggIndex) 534 } 535 return ec.row[ci], nil 536 } 537} 538 539// resolveColumnIndex turns an ID or PathExp into a table column index. 540func (ec evalContext) resolveColumnIndex(e spansql.Expr) (int, error) { 541 switch e := e.(type) { 542 case spansql.ID: 543 for i, col := range ec.cols { 544 if col.Name == e { 545 return i, nil 546 } 547 } 548 case spansql.PathExp: 549 for i, col := range ec.cols { 550 if pathExpEqual(e, col.Alias) { 551 return i, nil 552 } 553 } 554 } 555 return 0, fmt.Errorf("couldn't resolve [%s] as a table column", e.SQL()) 556} 557 558func (ec evalContext) evalPathExp(pe spansql.PathExp) (interface{}, error) { 559 // TODO: support more than only naming an aliased table column. 560 if i, err := ec.resolveColumnIndex(pe); err == nil { 561 return ec.row.copyDataElem(i), nil 562 } 563 return nil, fmt.Errorf("couldn't resolve path expression %s", pe.SQL()) 564} 565 566func (ec evalContext) evalID(id spansql.ID) (interface{}, error) { 567 if i, err := ec.resolveColumnIndex(id); err == nil { 568 return ec.row.copyDataElem(i), nil 569 } 570 if e, ok := ec.aliases[id]; ok { 571 // Make a copy of the context without this alias 572 // to prevent an evaluation cycle. 573 innerEC := ec 574 innerEC.aliases = make(map[spansql.ID]spansql.Expr) 575 for alias, e := range ec.aliases { 576 if alias != id { 577 innerEC.aliases[alias] = e 578 } 579 } 580 return innerEC.evalExpr(e) 581 } 582 return nil, fmt.Errorf("couldn't resolve identifier %s", id) 583} 584 585func (ec evalContext) coerceComparisonOpArgs(co spansql.ComparisonOp) (spansql.ComparisonOp, error) { 586 // https://cloud.google.com/spanner/docs/operators#comparison_operators 587 588 if co.RHS2 != nil { 589 // TODO: Handle co.RHS2 for BETWEEN. The rules for that aren't clear. 590 return co, nil 591 } 592 593 // Look for a string literal on LHS or RHS. 594 var err error 595 if slit, ok := co.LHS.(spansql.StringLiteral); ok { 596 co.LHS, err = ec.coerceString(co.RHS, slit) 597 return co, err 598 } 599 if slit, ok := co.RHS.(spansql.StringLiteral); ok { 600 co.RHS, err = ec.coerceString(co.LHS, slit) 601 return co, err 602 } 603 604 // TODO: Other coercion literals. The int64/float64 code elsewhere may be able to be simplified. 605 606 return co, nil 607} 608 609// coerceString converts a string literal into something compatible with the target expression. 610func (ec evalContext) coerceString(target spansql.Expr, slit spansql.StringLiteral) (spansql.Expr, error) { 611 ci, err := ec.colInfo(target) 612 if err != nil { 613 return nil, err 614 } 615 if ci.Type.Array { 616 return nil, fmt.Errorf("unable to coerce string literal %q to match array type", slit) 617 } 618 switch ci.Type.Base { 619 case spansql.String: 620 return slit, nil 621 case spansql.Date: 622 d, err := parseAsDate(string(slit)) 623 if err != nil { 624 return nil, fmt.Errorf("coercing string literal %q to DATE: %v", slit, err) 625 } 626 return coercedValue{ 627 val: d, 628 orig: slit, 629 }, nil 630 case spansql.Timestamp: 631 t, err := parseAsTimestamp(string(slit)) 632 if err != nil { 633 return nil, fmt.Errorf("coercing string literal %q to TIMESTAMP: %v", slit, err) 634 } 635 return coercedValue{ 636 val: t, 637 orig: slit, 638 }, nil 639 } 640 641 // TODO: Any others? 642 643 return nil, fmt.Errorf("unable to coerce string literal %q to match %v", slit, ci.Type) 644} 645 646func evalLiteralOrParam(lop spansql.LiteralOrParam, params queryParams) (int64, error) { 647 switch v := lop.(type) { 648 case spansql.IntegerLiteral: 649 return int64(v), nil 650 case spansql.Param: 651 return paramAsInteger(v, params) 652 default: 653 return 0, fmt.Errorf("LiteralOrParam with %T not supported", v) 654 } 655} 656 657func paramAsInteger(p spansql.Param, params queryParams) (int64, error) { 658 qp, ok := params[string(p)] 659 if !ok { 660 return 0, fmt.Errorf("unbound param %s", p.SQL()) 661 } 662 switch v := qp.Value.(type) { 663 default: 664 return 0, fmt.Errorf("can't interpret parameter %s (%s) value of type %T as integer", p.SQL(), qp.Type.SQL(), v) 665 case int64: 666 return v, nil 667 case string: 668 x, err := strconv.ParseInt(v, 10, 64) 669 if err != nil { 670 return 0, fmt.Errorf("bad int64 string %q: %v", v, err) 671 } 672 return x, nil 673 } 674} 675 676// compareValLists compares pair-wise elements of a and b. 677// If desc is not nil, it indicates which comparisons should be reversed. 678func compareValLists(a, b []interface{}, desc []bool) int { 679 for i := range a { 680 cmp := compareVals(a[i], b[i]) 681 if cmp == 0 { 682 continue 683 } 684 if desc != nil && desc[i] { 685 cmp = -cmp 686 } 687 return cmp 688 } 689 return 0 690} 691 692func compareVals(x, y interface{}) int { 693 // NULL is always the minimum possible value. 694 if x == nil && y == nil { 695 return 0 696 } else if x == nil { 697 return -1 698 } else if y == nil { 699 return 1 700 } 701 702 // TODO: coerce between more comparable types? factor this out for expressions other than comparisons. 703 704 switch x := x.(type) { 705 default: 706 panic(fmt.Sprintf("unhandled comparison on %T", x)) 707 case bool: 708 // false < true 709 y := y.(bool) 710 if !x && y { 711 return -1 712 } else if x && !y { 713 return 1 714 } 715 return 0 716 case int64: 717 if s, ok := y.(string); ok { 718 var err error 719 y, err = strconv.ParseInt(s, 10, 64) 720 if err != nil { 721 panic(fmt.Sprintf("bad int64 string %q: %v", s, err)) 722 } 723 } 724 if f, ok := y.(float64); ok { 725 // Coersion from INT64 to FLOAT64 is allowed. 726 return compareVals(x, f) 727 } 728 y := y.(int64) 729 if x < y { 730 return -1 731 } else if x > y { 732 return 1 733 } 734 return 0 735 case float64: 736 // Coersion from INT64 to FLOAT64 is allowed. 737 if i, ok := y.(int64); ok { 738 y = float64(i) 739 } 740 y := y.(float64) 741 if x < y { 742 return -1 743 } else if x > y { 744 return 1 745 } 746 return 0 747 case string: 748 return strings.Compare(x, y.(string)) 749 case civil.Date: 750 y := y.(civil.Date) 751 if x.Before(y) { 752 return -1 753 } else if x.After(y) { 754 return 1 755 } 756 return 0 757 case time.Time: 758 y := y.(time.Time) 759 if x.Before(y) { 760 return -1 761 } else if x.After(y) { 762 return 1 763 } 764 return 0 765 case []byte: 766 return bytes.Compare(x, y.([]byte)) 767 } 768} 769 770var ( 771 boolType = spansql.Type{Base: spansql.Bool} 772 int64Type = spansql.Type{Base: spansql.Int64} 773 float64Type = spansql.Type{Base: spansql.Float64} 774 stringType = spansql.Type{Base: spansql.String} 775) 776 777func (ec evalContext) colInfo(e spansql.Expr) (colInfo, error) { 778 // TODO: more types 779 switch e := e.(type) { 780 case spansql.BoolLiteral: 781 return colInfo{Type: boolType}, nil 782 case spansql.IntegerLiteral: 783 return colInfo{Type: int64Type}, nil 784 case spansql.StringLiteral: 785 return colInfo{Type: stringType}, nil 786 case spansql.BytesLiteral: 787 return colInfo{Type: spansql.Type{Base: spansql.Bytes}}, nil 788 case spansql.ArithOp: 789 t, err := ec.arithColType(e) 790 if err != nil { 791 return colInfo{}, err 792 } 793 return colInfo{Type: t}, nil 794 case spansql.LogicalOp, spansql.ComparisonOp, spansql.IsOp: 795 return colInfo{Type: spansql.Type{Base: spansql.Bool}}, nil 796 case spansql.PathExp, spansql.ID: 797 // TODO: support more than only naming a table column. 798 i, err := ec.resolveColumnIndex(e) 799 if err == nil { 800 return ec.cols[i], nil 801 } 802 // Let errors fall through. 803 case spansql.Param: 804 qp, ok := ec.params[string(e)] 805 if !ok { 806 return colInfo{}, fmt.Errorf("unbound param %s", e.SQL()) 807 } 808 return colInfo{Type: qp.Type}, nil 809 case spansql.Paren: 810 return ec.colInfo(e.Expr) 811 case spansql.Func: 812 _, t, err := ec.evalFunc(e) 813 if err != nil { 814 return colInfo{}, err 815 } 816 return colInfo{Type: t}, nil 817 case spansql.Array: 818 // Assume all element of an array literal have the same type. 819 if len(e) == 0 { 820 // TODO: What does the real Spanner do here? 821 return colInfo{Type: spansql.Type{Base: spansql.Int64, Array: true}}, nil 822 } 823 ci, err := ec.colInfo(e[0]) 824 if err != nil { 825 return colInfo{}, err 826 } 827 if ci.Type.Array { 828 return colInfo{}, fmt.Errorf("can't nest array literals") 829 } 830 ci.Type.Array = true 831 return ci, nil 832 case spansql.NullLiteral: 833 // There isn't necessarily something sensible here. 834 // Empirically, though, the real Spanner returns Int64. 835 return colInfo{Type: int64Type}, nil 836 case aggSentinel: 837 return colInfo{Type: e.Type, AggIndex: e.AggIndex}, nil 838 } 839 return colInfo{}, fmt.Errorf("can't deduce column type from expression [%s] (type %T)", e.SQL(), e) 840} 841 842func (ec evalContext) arithColType(ao spansql.ArithOp) (spansql.Type, error) { 843 // The type depends on the particular operator and the argument types. 844 // https://cloud.google.com/spanner/docs/functions-and-operators#arithmetic_operators 845 846 var lhs, rhs spansql.Type 847 var err error 848 if ao.LHS != nil { 849 ci, err := ec.colInfo(ao.LHS) 850 if err != nil { 851 return spansql.Type{}, err 852 } 853 lhs = ci.Type 854 } 855 ci, err := ec.colInfo(ao.RHS) 856 if err != nil { 857 return spansql.Type{}, err 858 } 859 rhs = ci.Type 860 861 switch ao.Op { 862 default: 863 return spansql.Type{}, fmt.Errorf("can't deduce column type from ArithOp [%s]", ao.SQL()) 864 case spansql.Neg, spansql.BitNot: 865 return rhs, nil 866 case spansql.Add, spansql.Sub, spansql.Mul: 867 if lhs == int64Type && rhs == int64Type { 868 return int64Type, nil 869 } 870 return float64Type, nil 871 case spansql.Div: 872 return float64Type, nil 873 case spansql.Concat: 874 if !lhs.Array { 875 return stringType, nil 876 } 877 return lhs, nil 878 case spansql.BitShl, spansql.BitShr, spansql.BitAnd, spansql.BitXor, spansql.BitOr: 879 // "All bitwise operators return the same type and the same length as the first operand." 880 return lhs, nil 881 } 882} 883 884func pathExpEqual(a, b spansql.PathExp) bool { 885 if len(a) != len(b) { 886 return false 887 } 888 for i := range a { 889 if a[i] != b[i] { 890 return false 891 } 892 } 893 return true 894} 895 896func evalLike(str, pat string) bool { 897 /* 898 % matches any number of chars. 899 _ matches a single char. 900 TODO: handle escaping 901 */ 902 903 // Lean on regexp for simplicity. 904 pat = regexp.QuoteMeta(pat) 905 if !strings.HasPrefix(pat, "%") { 906 pat = "^" + pat 907 } 908 if !strings.HasSuffix(pat, "%") { 909 pat = pat + "$" 910 } 911 pat = strings.Replace(pat, "%", ".*", -1) 912 pat = strings.Replace(pat, "_", ".", -1) 913 match, err := regexp.MatchString(pat, str) 914 if err != nil { 915 panic(fmt.Sprintf("internal error: constructed bad regexp /%s/: %v", pat, err)) 916 } 917 return match 918} 919