github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/eval_test.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tree_test
    12  
    13  import (
    14  	"context"
    15  	gosql "database/sql"
    16  	"fmt"
    17  	"path/filepath"
    18  	"regexp"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/cockroachdb/cockroach/pkg/base"
    23  	"github.com/cockroachdb/cockroach/pkg/col/coldata"
    24  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/colexec"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/execinfra"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/opt/exec/execbuilder"
    30  	"github.com/cockroachdb/cockroach/pkg/sql/opt/optbuilder"
    31  	"github.com/cockroachdb/cockroach/pkg/sql/opt/xform"
    32  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    33  	"github.com/cockroachdb/cockroach/pkg/sql/rowexec"
    34  	_ "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
    35  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    36  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    37  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    38  	"github.com/cockroachdb/cockroach/pkg/testutils"
    39  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    40  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    41  	"github.com/cockroachdb/datadriven"
    42  	"github.com/stretchr/testify/require"
    43  )
    44  
    45  func TestEval(t *testing.T) {
    46  	defer leaktest.AfterTest(t)()
    47  	ctx := context.Background()
    48  	evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings())
    49  	defer evalCtx.Stop(ctx)
    50  
    51  	walk := func(t *testing.T, getExpr func(*testing.T, *datadriven.TestData) string) {
    52  		datadriven.Walk(t, filepath.Join("testdata", "eval"), func(t *testing.T, path string) {
    53  			datadriven.RunTest(t, path, func(t *testing.T, d *datadriven.TestData) string {
    54  				if d.Cmd != "eval" {
    55  					t.Fatalf("unsupported command %s", d.Cmd)
    56  				}
    57  				return getExpr(t, d) + "\n"
    58  			})
    59  		})
    60  	}
    61  
    62  	walkExpr := func(t *testing.T, getExpr func(tree.Expr) (tree.TypedExpr, error)) {
    63  		walk(t, func(t *testing.T, d *datadriven.TestData) string {
    64  			expr, err := parser.ParseExpr(d.Input)
    65  			if err != nil {
    66  				t.Fatalf("%s: %v", d.Input, err)
    67  			}
    68  			e, err := getExpr(expr)
    69  			if err != nil {
    70  				return fmt.Sprint(err)
    71  			}
    72  			r, err := e.Eval(evalCtx)
    73  			if err != nil {
    74  				return fmt.Sprint(err)
    75  			}
    76  			return r.String()
    77  		})
    78  	}
    79  
    80  	t.Run("opt", func(t *testing.T) {
    81  		walkExpr(t, func(e tree.Expr) (tree.TypedExpr, error) {
    82  			return optBuildScalar(evalCtx, e)
    83  		})
    84  	})
    85  
    86  	t.Run("no-opt", func(t *testing.T) {
    87  		walkExpr(t, func(e tree.Expr) (tree.TypedExpr, error) {
    88  			// expr.TypeCheck to avoid constant folding.
    89  			semaCtx := tree.MakeSemaContext()
    90  			typedExpr, err := e.TypeCheck(ctx, &semaCtx, types.Any)
    91  			if err != nil {
    92  				return nil, err
    93  			}
    94  			return evalCtx.NormalizeExpr(typedExpr)
    95  		})
    96  	})
    97  
    98  	// The opt and no-opt tests don't do an end-to-end SQL test. Do that
    99  	// here by executing a SELECT. In order to make the output be the same
   100  	// we have to also figure out what the expected output type is so we
   101  	// can correctly format the datum.
   102  	t.Run("sql", func(t *testing.T) {
   103  		s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{})
   104  		defer s.Stopper().Stop(ctx)
   105  
   106  		walk(t, func(t *testing.T, d *datadriven.TestData) string {
   107  			var res gosql.NullString
   108  			if err := sqlDB.QueryRow(fmt.Sprintf("SELECT (%s)::STRING", d.Input)).Scan(&res); err != nil {
   109  				return strings.TrimPrefix(err.Error(), "pq: ")
   110  			}
   111  			if !res.Valid {
   112  				return "NULL"
   113  			}
   114  
   115  			// We have a non-null result. We can't just return
   116  			// res.String here because these strings don't
   117  			// match the datum.String() representations. For
   118  			// example, a bitarray has a res.String of something
   119  			// like `1001001` but the datum representation is
   120  			// `B'1001001'`. Thus we have to parse res.String (a
   121  			// SQL result) back into a datum and return that.
   122  
   123  			expr, err := parser.ParseExpr(d.Input)
   124  			if err != nil {
   125  				t.Fatal(err)
   126  			}
   127  			// expr.TypeCheck to avoid constant folding.
   128  			semaCtx := tree.MakeSemaContext()
   129  			typedExpr, err := expr.TypeCheck(ctx, &semaCtx, types.Any)
   130  			if err != nil {
   131  				// An error here should have been found above by QueryRow.
   132  				t.Fatal(err)
   133  			}
   134  
   135  			switch typedExpr.ResolvedType().Family() {
   136  			case types.TupleFamily:
   137  				// ParseAndRequireString doesn't handle tuples, so we have to convert them ourselves.
   138  				var datums tree.Datums
   139  				// Fetch the original expression's tuple values.
   140  				tuple := typedExpr.(*tree.Tuple)
   141  				for i, s := range strings.Split(res.String[1:len(res.String)-1], ",") {
   142  					if s == "" {
   143  						continue
   144  					}
   145  					// Figure out the type of the tuple value.
   146  					expr, err := tuple.Exprs[i].TypeCheck(ctx, &semaCtx, types.Any)
   147  					if err != nil {
   148  						t.Fatal(err)
   149  					}
   150  					// Now parse the new string as the expected type.
   151  					datum, err := tree.ParseAndRequireString(expr.ResolvedType(), s, evalCtx)
   152  					if err != nil {
   153  						t.Errorf("%s: %s", err, s)
   154  						return err.Error()
   155  					}
   156  					datums = append(datums, datum)
   157  				}
   158  				return tree.NewDTuple(typedExpr.ResolvedType(), datums...).String()
   159  			}
   160  			datum, err := tree.ParseAndRequireString(typedExpr.ResolvedType(), res.String, evalCtx)
   161  			if err != nil {
   162  				t.Errorf("%s: %s", err, res.String)
   163  				return err.Error()
   164  			}
   165  			return datum.String()
   166  		})
   167  	})
   168  
   169  	t.Run("vectorized", func(t *testing.T) {
   170  		walk(t, func(t *testing.T, d *datadriven.TestData) string {
   171  			if d.Input == "B'11111111111111111111111110000101'::int4" {
   172  				// Skip this test: https://github.com/cockroachdb/cockroach/pull/40790#issuecomment-532597294.
   173  				return strings.TrimSpace(d.Expected)
   174  			}
   175  			flowCtx := &execinfra.FlowCtx{
   176  				EvalCtx: evalCtx,
   177  			}
   178  			memMonitor := execinfra.NewTestMemMonitor(ctx, cluster.MakeTestingClusterSettings())
   179  			defer memMonitor.Stop(ctx)
   180  			acc := memMonitor.MakeBoundAccount()
   181  			defer acc.Close(ctx)
   182  			expr, err := parser.ParseExpr(d.Input)
   183  			require.NoError(t, err)
   184  			if _, ok := expr.(*tree.RangeCond); ok {
   185  				// RangeCond gets normalized to comparison expressions and its Eval
   186  				// method returns an error, so skip it for execution.
   187  				return strings.TrimSpace(d.Expected)
   188  			}
   189  			semaCtx := tree.MakeSemaContext()
   190  			typedExpr, err := expr.TypeCheck(ctx, &semaCtx, types.Any)
   191  			if err != nil {
   192  				// Skip this test as it's testing an expected error which would be
   193  				// caught before execution.
   194  				return strings.TrimSpace(d.Expected)
   195  			}
   196  			typs := []*types.T{typedExpr.ResolvedType()}
   197  
   198  			// inputTyps has no relation to the actual expression result type. Used
   199  			// for generating a batch.
   200  			inputTyps := []*types.T{types.Int}
   201  
   202  			batchesReturned := 0
   203  			args := colexec.NewColOperatorArgs{
   204  				Spec: &execinfrapb.ProcessorSpec{
   205  					Input: []execinfrapb.InputSyncSpec{{
   206  						Type:        execinfrapb.InputSyncSpec_UNORDERED,
   207  						ColumnTypes: inputTyps,
   208  					}},
   209  					Core: execinfrapb.ProcessorCoreUnion{
   210  						Noop: &execinfrapb.NoopCoreSpec{},
   211  					},
   212  					Post: execinfrapb.PostProcessSpec{
   213  						RenderExprs: []execinfrapb.Expression{{Expr: d.Input}},
   214  					},
   215  				},
   216  				Inputs: []colexecbase.Operator{
   217  					&colexecbase.CallbackOperator{
   218  						NextCb: func(_ context.Context) coldata.Batch {
   219  							if batchesReturned > 0 {
   220  								return coldata.ZeroBatch
   221  							}
   222  							// It doesn't matter what types we create the input batch with.
   223  							batch := coldata.NewMemBatch(inputTyps, coldata.StandardColumnFactory)
   224  							batch.SetLength(1)
   225  							batchesReturned++
   226  							return batch
   227  						},
   228  					},
   229  				},
   230  				StreamingMemAccount: &acc,
   231  				// Unsupported post processing specs are wrapped and run through the
   232  				// row execution engine.
   233  				ProcessorConstructor: rowexec.NewProcessor,
   234  			}
   235  			args.TestingKnobs.UseStreamingMemAccountForBuffering = true
   236  			result, err := colexec.NewColOperator(ctx, flowCtx, args)
   237  			if testutils.IsError(err, "unsupported type") {
   238  				// Skip this test as execution is not supported by the vectorized
   239  				// engine.
   240  				return strings.TrimSpace(d.Expected)
   241  			} else {
   242  				require.NoError(t, err)
   243  			}
   244  
   245  			mat, err := colexec.NewMaterializer(
   246  				flowCtx,
   247  				0, /* processorID */
   248  				result.Op,
   249  				typs,
   250  				nil, /* output */
   251  				nil, /* metadataSourcesQueue */
   252  				nil, /* toClose */
   253  				nil, /* outputStatsToTrace */
   254  				nil, /* cancelFlow */
   255  			)
   256  			require.NoError(t, err)
   257  
   258  			var (
   259  				row  sqlbase.EncDatumRow
   260  				meta *execinfrapb.ProducerMetadata
   261  			)
   262  			ctx = mat.Start(ctx)
   263  			row, meta = mat.Next()
   264  			if meta != nil {
   265  				if meta.Err != nil {
   266  					return fmt.Sprint(meta.Err)
   267  				}
   268  				t.Fatalf("unexpected metadata: %+v", meta)
   269  			}
   270  			if row == nil {
   271  				// Might be some metadata.
   272  				if meta := mat.DrainHelper(); meta.Err != nil {
   273  					t.Fatalf("unexpected error: %s", meta.Err)
   274  				}
   275  				t.Fatal("unexpected end of input")
   276  			}
   277  			return row[0].Datum.String()
   278  		})
   279  	})
   280  }
   281  
   282  func optBuildScalar(evalCtx *tree.EvalContext, e tree.Expr) (tree.TypedExpr, error) {
   283  	var o xform.Optimizer
   284  	o.Init(evalCtx, nil /* catalog */)
   285  	ctx := context.Background()
   286  	semaCtx := tree.MakeSemaContext()
   287  	b := optbuilder.NewScalar(ctx, &semaCtx, evalCtx, o.Factory())
   288  	if err := b.Build(e); err != nil {
   289  		return nil, err
   290  	}
   291  
   292  	bld := execbuilder.New(nil /* factory */, o.Memo(), nil /* catalog */, o.Memo().RootExpr(), evalCtx)
   293  	ivh := tree.MakeIndexedVarHelper(nil /* container */, 0)
   294  
   295  	expr, err := bld.BuildScalar(&ivh)
   296  	if err != nil {
   297  		return nil, err
   298  	}
   299  	return expr, nil
   300  }
   301  
   302  func TestTimeConversion(t *testing.T) {
   303  	defer leaktest.AfterTest(t)()
   304  	tests := []struct {
   305  		start     string
   306  		format    string
   307  		tm        string
   308  		revformat string
   309  		reverse   string
   310  	}{
   311  		// %a %A %b %B (+ %Y)
   312  		{`Wed Oct 05 2016`, `%a %b %d %Y`, `2016-10-05 00:00:00+00:00`, ``, ``},
   313  		{`Wednesday October 05 2016`, `%A %B %d %Y`, `2016-10-05 00:00:00+00:00`, ``, ``},
   314  		// %c
   315  		{`Wed Oct 5 01:02:03 2016`, `%c`, `2016-10-05 01:02:03+00:00`, ``, ``},
   316  		// %C %d (+ %m %y)
   317  		{`20 06 10 12`, `%C %y %m %d`, `2006-10-12 00:00:00+00:00`, ``, ``},
   318  		// %D
   319  		{`10/12/06`, `%D`, `2006-10-12 00:00:00+00:00`, ``, ``},
   320  		// %e (+ %Y %m)
   321  		{`2006 10  3`, `%Y %m %e`, `2006-10-03 00:00:00+00:00`, ``, ``},
   322  		// %f (+ %c)
   323  		{`Wed Oct 5 01:02:03 2016 .123`, `%c .%f`, `2016-10-05 01:02:03.123+00:00`, `.%f`, `.123000`},
   324  		{`Wed Oct 5 01:02:03 2016 .123456`, `%c .%f`, `2016-10-05 01:02:03.123456+00:00`, `.%f`, `.123456`},
   325  		{`Wed Oct 5 01:02:03 2016 .999999`, `%c .%f`, `2016-10-05 01:02:03.999999+00:00`, `.%f`, `.999999`},
   326  		// %F
   327  		{`2006-10-03`, `%F`, `2006-10-03 00:00:00+00:00`, ``, ``},
   328  		// %h (+ %Y %d)
   329  		{`2006 Oct 03`, `%Y %h %d`, `2006-10-03 00:00:00+00:00`, ``, ``},
   330  		// %H (+ %S %M)
   331  		{`20061012 01:03:02`, `%Y%m%d %H:%S:%M`, `2006-10-12 01:02:03+00:00`, ``, ``},
   332  		// %I (+ %Y %m %d)
   333  		{`20161012 11`, `%Y%m%d %I`, `2016-10-12 11:00:00+00:00`, ``, ``},
   334  		// %j (+ %Y)
   335  		{`2016 286`, `%Y %j`, `2016-10-12 00:00:00+00:00`, ``, ``},
   336  		// %k (+ %Y %m %d)
   337  		{`20061012 23`, `%Y%m%d %k`, `2006-10-12 23:00:00+00:00`, ``, ``},
   338  		// %l (+ %Y %m %d %p)
   339  		{`20061012  5 PM`, `%Y%m%d %l %p`, `2006-10-12 17:00:00+00:00`, ``, ``},
   340  		// %n (+ %Y %m %d)
   341  		{"2006\n10\n03", `%Y%n%m%n%d`, `2006-10-03 00:00:00+00:00`, ``, ``},
   342  		// %p cannot be parsed before hour specifiers, so be sure that
   343  		// they appear in this order.
   344  		{`20161012 11 PM`, `%Y%m%d %I %p`, `2016-10-12 23:00:00+00:00`, ``, ``},
   345  		{`20161012 11 AM`, `%Y%m%d %I %p`, `2016-10-12 11:00:00+00:00`, ``, ``},
   346  		// %r
   347  		{`20161012 11:02:03 PM`, `%Y%m%d %r`, `2016-10-12 23:02:03+00:00`, ``, ``},
   348  		// %R
   349  		{`20161012 11:02`, `%Y%m%d %R`, `2016-10-12 11:02:00+00:00`, ``, ``},
   350  		// %s
   351  		{`1491920586`, `%s`, `2017-04-11 14:23:06+00:00`, ``, ``},
   352  		// %t (+ %Y %m %d)
   353  		{"2006\t10\t03", `%Y%t%m%t%d`, `2006-10-03 00:00:00+00:00`, ``, ``},
   354  		// %T (+ %Y %m %d)
   355  		{`20061012 01:02:03`, `%Y%m%d %T`, `2006-10-12 01:02:03+00:00`, ``, ``},
   356  		// %U %u (+ %Y)
   357  		{`2018 10 4`, `%Y %U %u`, `2018-03-15 00:00:00+00:00`, ``, ``},
   358  		// %W %w (+ %Y)
   359  		{`2018 10 4`, `%Y %W %w`, `2018-03-08 00:00:00+00:00`, ``, ``},
   360  		// %x
   361  		{`10/12/06`, `%x`, `2006-10-12 00:00:00+00:00`, ``, ``},
   362  		// %X
   363  		{`20061012 01:02:03`, `%Y%m%d %X`, `2006-10-12 01:02:03+00:00`, ``, ``},
   364  		// %y (+ %m %d)
   365  		{`000101`, `%y%m%d`, `2000-01-01 00:00:00+00:00`, ``, ``},
   366  		{`680101`, `%y%m%d`, `2068-01-01 00:00:00+00:00`, ``, ``},
   367  		{`690101`, `%y%m%d`, `1969-01-01 00:00:00+00:00`, ``, ``},
   368  		{`990101`, `%y%m%d`, `1999-01-01 00:00:00+00:00`, ``, ``},
   369  		// %Y
   370  		{`19000101`, `%Y%m%d`, `1900-01-01 00:00:00+00:00`, ``, ``},
   371  		{`20000101`, `%Y%m%d`, `2000-01-01 00:00:00+00:00`, ``, ``},
   372  		{`30000101`, `%Y%m%d`, `3000-01-01 00:00:00+00:00`, ``, ``},
   373  		// %z causes the time zone to adjust the time when parsing, but the time zone information
   374  		// is not retained when printing the timestamp out back.
   375  		{`20160101 13:00 +0655`, `%Y%m%d %H:%M %z`, `2016-01-01 06:05:00+00:00`, `%Y%m%d %H:%M %z`, `20160101 06:05 +0000`},
   376  	}
   377  
   378  	for _, test := range tests {
   379  		ctx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   380  		defer ctx.Mon.Stop(context.Background())
   381  		exprStr := fmt.Sprintf("experimental_strptime('%s', '%s')", test.start, test.format)
   382  		expr, err := parser.ParseExpr(exprStr)
   383  		if err != nil {
   384  			t.Errorf("%s: %v", exprStr, err)
   385  			continue
   386  		}
   387  		semaCtx := tree.MakeSemaContext()
   388  		typedExpr, err := expr.TypeCheck(context.Background(), &semaCtx, types.Timestamp)
   389  		if err != nil {
   390  			t.Errorf("%s: %v", exprStr, err)
   391  			continue
   392  		}
   393  		r, err := typedExpr.Eval(ctx)
   394  		if err != nil {
   395  			t.Errorf("%s: %v", exprStr, err)
   396  			continue
   397  		}
   398  		ts, ok := r.(*tree.DTimestampTZ)
   399  		if !ok {
   400  			t.Errorf("%s: result not a timestamp: %s", exprStr, r)
   401  			continue
   402  		}
   403  
   404  		tmS := ts.String()
   405  		tmS = tmS[1 : len(tmS)-1] // strip the quote delimiters
   406  		if tmS != test.tm {
   407  			t.Errorf("%s: got %q, expected %q", exprStr, tmS, test.tm)
   408  			continue
   409  		}
   410  
   411  		revfmt := test.format
   412  		if test.revformat != "" {
   413  			revfmt = test.revformat
   414  		}
   415  
   416  		ref := test.start
   417  		if test.reverse != "" {
   418  			ref = test.reverse
   419  		}
   420  
   421  		exprStr = fmt.Sprintf("experimental_strftime('%s'::timestamp, '%s')", tmS, revfmt)
   422  		expr, err = parser.ParseExpr(exprStr)
   423  		if err != nil {
   424  			t.Errorf("%s: %v", exprStr, err)
   425  			continue
   426  		}
   427  		typedExpr, err = expr.TypeCheck(context.Background(), &semaCtx, types.Timestamp)
   428  		if err != nil {
   429  			t.Errorf("%s: %v", exprStr, err)
   430  			continue
   431  		}
   432  		r, err = typedExpr.Eval(ctx)
   433  		if err != nil {
   434  			t.Errorf("%s: %v", exprStr, err)
   435  			continue
   436  		}
   437  		rs, ok := r.(*tree.DString)
   438  		if !ok {
   439  			t.Errorf("%s: result not a string: %s", exprStr, r)
   440  			continue
   441  		}
   442  		revS := string(*rs)
   443  		if ref != revS {
   444  			t.Errorf("%s: got %q, expected %q", exprStr, revS, ref)
   445  		}
   446  	}
   447  }
   448  
   449  func TestEvalError(t *testing.T) {
   450  	defer leaktest.AfterTest(t)()
   451  	testData := []struct {
   452  		expr     string
   453  		expected string
   454  	}{
   455  		{`1 % 0`, `zero modulus`},
   456  		{`1 / 0`, `division by zero`},
   457  		{`1::float / 0::float`, `division by zero`},
   458  		{`1 // 0`, `division by zero`},
   459  		{`1.5 / 0`, `division by zero`},
   460  		{`'11h2m'::interval / 0`, `division by zero`},
   461  		{`'11h2m'::interval / 0.0::float`, `division by zero`},
   462  		{`'???'::bool`,
   463  			`could not parse "???" as type bool`},
   464  		{`'foo'::int`,
   465  			`could not parse "foo" as type int: strconv.ParseInt: parsing "foo": invalid syntax`},
   466  		{`'3\r2'::int`,
   467  			`could not parse "3\\r2" as type int: strconv.ParseInt: parsing "3\\r2": invalid syntax`},
   468  		{`'bar'::float`,
   469  			`could not parse "bar" as type float: strconv.ParseFloat: parsing "bar": invalid syntax`},
   470  		{`'baz'::decimal`,
   471  			`could not parse "baz" as type decimal`},
   472  		{`'2010-09-28 12:00:00.1q'::date`,
   473  			`parsing as type date: could not parse "2010-09-28 12:00:00.1q"`},
   474  		{`'12:00:00q'::time`, `could not parse "12:00:00q" as type time`},
   475  		{`'2010-09-28 12:00.1 MST'::timestamp`,
   476  			`unimplemented: timestamp abbreviations not supported`},
   477  		{`'abcd'::interval`,
   478  			`could not parse "abcd" as type interval: interval: missing unit`},
   479  		{`'1- 2:3:4 9'::interval`,
   480  			`could not parse "1- 2:3:4 9" as type interval: invalid input syntax for type interval 1- 2:3:4 9`},
   481  		{`e'\\xdedf0d36174'::BYTES`, `could not parse "\\xdedf0d36174" as type bytes: encoding/hex: odd length hex string`},
   482  		{`ARRAY[NULL, ARRAY[1, 2]]`, `multidimensional arrays must have array expressions with matching dimensions`},
   483  		{`ARRAY[ARRAY[1, 2], NULL]`, `multidimensional arrays must have array expressions with matching dimensions`},
   484  		{`ARRAY[ARRAY[1, 2], ARRAY[1]]`, `multidimensional arrays must have array expressions with matching dimensions`},
   485  		// TODO(pmattis): Check for overflow.
   486  		// {`~0 + 1`, `0`},
   487  		{`9223372036854775807::int + 1::int`, `integer out of range`},
   488  		{`-9223372036854775807::int + -2::int`, `integer out of range`},
   489  		{`-9223372036854775807::int + -9223372036854775807::int`, `integer out of range`},
   490  		{`9223372036854775807::int + 9223372036854775807::int`, `integer out of range`},
   491  		{`9223372036854775807::int - -1::int`, `integer out of range`},
   492  		{`-9223372036854775807::int - 2::int`, `integer out of range`},
   493  		{`-9223372036854775807::int - 9223372036854775807::int`, `integer out of range`},
   494  		{`9223372036854775807::int - -9223372036854775807::int`, `integer out of range`},
   495  		{`4611686018427387904::int * 2::int`, `integer out of range`},
   496  		{`4611686018427387904::int * 2::int`, `integer out of range`},
   497  		{`(-9223372036854775807:::int - 1) * -1:::int`, `integer out of range`},
   498  		{`123 ^ 100`, `integer out of range`},
   499  		{`power(123, 100)`, `integer out of range`},
   500  		// Although these next two tests are valid integers, a float cannot represent
   501  		// them exactly, and so rounds them to a larger number that is out of bounds
   502  		// for an int. Thus, they should fail during this conversion.
   503  		{`9223372036854775807::float::int`, `integer out of range`},
   504  		{`-9223372036854775808::float::int`, `integer out of range`},
   505  		// The two smallest floats that cannot be converted to an int.
   506  		{`9223372036854775296::float::int`, `integer out of range`},
   507  		{`-9223372036854775296::float::int`, `integer out of range`},
   508  		{`1e500::decimal::int`, `integer out of range`},
   509  		{`1e500::decimal::float`, `float out of range`},
   510  		{`1e300::decimal::float::int`, `integer out of range`},
   511  		{`'Inf'::decimal::int`, `integer out of range`},
   512  		{`'NaN'::decimal::int`, `integer out of range`},
   513  		{`'Inf'::float::int`, `integer out of range`},
   514  		{`'NaN'::float::int`, `integer out of range`},
   515  		{`'1.1'::int`, `could not parse "1.1" as type int`},
   516  		{`IFERROR(1/0, 123, 'unknown')`, `division by zero`},
   517  		{`ISERROR(1/0, 'unknown')`, `division by zero`},
   518  		{`like_escape('___', '\___', 'abc')`, `invalid escape string`},
   519  		{`like_escape('abc', 'abc', 'a日')`, `invalid escape string`},
   520  		{`like_escape('abc', 'abc', '漢日')`, `invalid escape string`},
   521  		{`like_escape('__', '_', '_')`, `LIKE pattern must not end with escape character`},
   522  		{`like_escape('%%', '%', '%')`, `LIKE pattern must not end with escape character`},
   523  		{`like_escape('__', '___', '_')`, `LIKE pattern must not end with escape character`},
   524  		{`like_escape('%%', '%%%', '%')`, `LIKE pattern must not end with escape character`},
   525  		{`like_escape('abc', 'ab%', '%')`, `LIKE pattern must not end with escape character`},
   526  		{`like_escape('abc', '%b%', '%')`, `LIKE pattern must not end with escape character`},
   527  		{`like_escape('abc', 'ab_', '_')`, `LIKE pattern must not end with escape character`},
   528  		{`like_escape('abc', '%b_', '_')`, `LIKE pattern must not end with escape character`},
   529  		{`like_escape('abc', '%b漢', '漢')`, `LIKE pattern must not end with escape character`},
   530  		{`similar_to_escape('abc', '-a-b-c', '-')`, `error parsing regexp: invalid escape sequence`},
   531  		{`similar_to_escape('a(b)c', '%((_)_', '(')`, `error parsing regexp: unexpected )`},
   532  		{`convert_from('\xaaaa'::bytea, 'woo')`, `convert_from(): invalid source encoding name "woo"`},
   533  		{`convert_from('\xaaaa'::bytea, 'utf8')`, `convert_from(): invalid byte sequence for encoding "UTF8"`},
   534  		{`convert_to('abc', 'woo')`, `convert_to(): invalid destination encoding name "woo"`},
   535  		{`convert_to('漢', 'latin1')`, `convert_to(): character '漢' has no representation in encoding "LATIN1"`},
   536  		{`'123'::BIT`, `could not parse string as bit array: "2" is not a valid binary digit`},
   537  		{`B'1001' & B'101'`, `cannot AND bit strings of different sizes`},
   538  		{`B'1001' | B'101'`, `cannot OR bit strings of different sizes`},
   539  		{`B'1001' # B'101'`, `cannot XOR bit strings of different sizes`},
   540  	}
   541  	ctx := context.Background()
   542  	for _, d := range testData {
   543  		expr, err := parser.ParseExpr(d.expr)
   544  		if err != nil {
   545  			t.Fatalf("%s: %v", d.expr, err)
   546  		}
   547  		semaCtx := tree.MakeSemaContext()
   548  		typedExpr, err := tree.TypeCheck(ctx, expr, &semaCtx, types.Any)
   549  		if err == nil {
   550  			evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   551  			defer evalCtx.Stop(context.Background())
   552  			_, err = typedExpr.Eval(evalCtx)
   553  		}
   554  		if !testutils.IsError(err, strings.Replace(regexp.QuoteMeta(d.expected), `\.\*`, `.*`, -1)) {
   555  			t.Errorf("%s: expected %s, but found %v", d.expr, d.expected, err)
   556  		}
   557  	}
   558  }