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