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