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

     1  // Copyright 2016 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 builtins
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  	"math/rand"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    23  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    24  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestCategory(t *testing.T) {
    30  	defer leaktest.AfterTest(t)()
    31  	if expected, actual := categoryString, builtins["lower"].props.Category; expected != actual {
    32  		t.Fatalf("bad category: expected %q got %q", expected, actual)
    33  	}
    34  	if expected, actual := categoryString, builtins["length"].props.Category; expected != actual {
    35  		t.Fatalf("bad category: expected %q got %q", expected, actual)
    36  	}
    37  	if expected, actual := categoryDateAndTime, builtins["now"].props.Category; expected != actual {
    38  		t.Fatalf("bad category: expected %q got %q", expected, actual)
    39  	}
    40  	if expected, actual := categorySystemInfo, builtins["version"].props.Category; expected != actual {
    41  		t.Fatalf("bad category: expected %q got %q", expected, actual)
    42  	}
    43  }
    44  
    45  // TestGenerateUniqueIDOrder verifies the expected ordering of
    46  // GenerateUniqueID.
    47  func TestGenerateUniqueIDOrder(t *testing.T) {
    48  	defer leaktest.AfterTest(t)()
    49  	tests := []tree.DInt{
    50  		GenerateUniqueID(0, 0),
    51  		GenerateUniqueID(1, 0),
    52  		GenerateUniqueID(2<<15, 0),
    53  		GenerateUniqueID(0, 1),
    54  		GenerateUniqueID(0, 10000),
    55  		GenerateUniqueInt(0),
    56  	}
    57  	prev := tests[0]
    58  	for _, tc := range tests[1:] {
    59  		if tc <= prev {
    60  			t.Fatalf("%d > %d", tc, prev)
    61  		}
    62  	}
    63  }
    64  
    65  func TestStringToArrayAndBack(t *testing.T) {
    66  	defer leaktest.AfterTest(t)()
    67  	// s allows us to have a string pointer literal.
    68  	s := func(x string) *string { return &x }
    69  	fs := func(x *string) string {
    70  		if x != nil {
    71  			return *x
    72  		}
    73  		return "<nil>"
    74  	}
    75  	cases := []struct {
    76  		input    string
    77  		sep      *string
    78  		nullStr  *string
    79  		expected []*string
    80  	}{
    81  		{`abcxdef`, s(`x`), nil, []*string{s(`abc`), s(`def`)}},
    82  		{`xxx`, s(`x`), nil, []*string{s(``), s(``), s(``), s(``)}},
    83  		{`xxx`, s(`xx`), nil, []*string{s(``), s(`x`)}},
    84  		{`abcxdef`, s(``), nil, []*string{s(`abcxdef`)}},
    85  		{`abcxdef`, s(`abcxdef`), nil, []*string{s(``), s(``)}},
    86  		{`abcxdef`, s(`x`), s(`abc`), []*string{nil, s(`def`)}},
    87  		{`abcxdef`, s(`x`), s(`x`), []*string{s(`abc`), s(`def`)}},
    88  		{`abcxdef`, s(`x`), s(``), []*string{s(`abc`), s(`def`)}},
    89  		{``, s(`x`), s(``), []*string{}},
    90  		{``, s(``), s(``), []*string{}},
    91  		{``, s(`x`), nil, []*string{}},
    92  		{``, s(``), nil, []*string{}},
    93  		{`abcxdef`, nil, nil, []*string{s(`a`), s(`b`), s(`c`), s(`x`), s(`d`), s(`e`), s(`f`)}},
    94  		{`abcxdef`, nil, s(`abc`), []*string{s(`a`), s(`b`), s(`c`), s(`x`), s(`d`), s(`e`), s(`f`)}},
    95  		{`abcxdef`, nil, s(`x`), []*string{s(`a`), s(`b`), s(`c`), nil, s(`d`), s(`e`), s(`f`)}},
    96  		{`abcxdef`, nil, s(``), []*string{s(`a`), s(`b`), s(`c`), s(`x`), s(`d`), s(`e`), s(`f`)}},
    97  		{``, nil, s(``), []*string{}},
    98  		{``, nil, nil, []*string{}},
    99  	}
   100  
   101  	for _, tc := range cases {
   102  		t.Run(fmt.Sprintf("string_to_array(%q, %q)", tc.input, fs(tc.sep)), func(t *testing.T) {
   103  			result, err := stringToArray(tc.input, tc.sep, tc.nullStr)
   104  			if err != nil {
   105  				t.Fatal(err)
   106  			}
   107  
   108  			expectedArray := tree.NewDArray(types.String)
   109  			for _, s := range tc.expected {
   110  				datum := tree.DNull
   111  				if s != nil {
   112  					datum = tree.NewDString(*s)
   113  				}
   114  				if err := expectedArray.Append(datum); err != nil {
   115  					t.Fatal(err)
   116  				}
   117  			}
   118  
   119  			evalContext := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   120  			if result.Compare(evalContext, expectedArray) != 0 {
   121  				t.Errorf("expected %v, got %v", tc.expected, result)
   122  			}
   123  
   124  			if tc.sep == nil {
   125  				return
   126  			}
   127  
   128  			s, err := arrayToString(result.(*tree.DArray), *tc.sep, tc.nullStr)
   129  			if err != nil {
   130  				t.Fatal(err)
   131  			}
   132  			if s == tree.DNull {
   133  				t.Errorf("expected not null, found null")
   134  			}
   135  
   136  			ds := s.(*tree.DString)
   137  			fmt.Println(ds)
   138  			if string(*ds) != tc.input {
   139  				t.Errorf("original %s, roundtripped %s", tc.input, s)
   140  			}
   141  		})
   142  	}
   143  }
   144  
   145  func TestEscapeFormat(t *testing.T) {
   146  	defer leaktest.AfterTest(t)()
   147  	testCases := []struct {
   148  		bytes []byte
   149  		str   string
   150  	}{
   151  		{[]byte{}, ``},
   152  		{[]byte{'a', 'b', 'c'}, `abc`},
   153  		{[]byte{'a', 'b', 'c', 'd'}, `abcd`},
   154  		{[]byte{'a', 'b', 0, 'd'}, `ab\000d`},
   155  		{[]byte{'a', 'b', 0, 0, 'd'}, `ab\000\000d`},
   156  		{[]byte{'a', 'b', 0, 'a', 'b', 'c', 0, 'd'}, `ab\000abc\000d`},
   157  		{[]byte{'a', 'b', 0, 0}, `ab\000\000`},
   158  		{[]byte{'a', 'b', '\\', 'd'}, `ab\\d`},
   159  		{[]byte{'a', 'b', 200, 'd'}, `ab\310d`},
   160  		{[]byte{'a', 'b', 7, 'd'}, "ab\x07d"},
   161  	}
   162  
   163  	for _, tc := range testCases {
   164  		t.Run(tc.str, func(t *testing.T) {
   165  			result := encodeEscape(tc.bytes)
   166  			if result != tc.str {
   167  				t.Fatalf("expected %q, got %q", tc.str, result)
   168  			}
   169  
   170  			decodedResult, err := decodeEscape(tc.str)
   171  			if err != nil {
   172  				t.Fatal(err)
   173  			}
   174  			if !bytes.Equal(decodedResult, tc.bytes) {
   175  				t.Fatalf("expected %q, got %#v", tc.bytes, decodedResult)
   176  			}
   177  		})
   178  	}
   179  }
   180  
   181  func TestEscapeFormatRandom(t *testing.T) {
   182  	defer leaktest.AfterTest(t)()
   183  	for i := 0; i < 1000; i++ {
   184  		b := make([]byte, rand.Intn(100))
   185  		for j := 0; j < len(b); j++ {
   186  			b[j] = byte(rand.Intn(256))
   187  		}
   188  		str := encodeEscape(b)
   189  		decodedResult, err := decodeEscape(str)
   190  		if err != nil {
   191  			t.Fatal(err)
   192  		}
   193  		if !bytes.Equal(decodedResult, b) {
   194  			t.Fatalf("generated %#v, after round-tripping got %#v", b, decodedResult)
   195  		}
   196  	}
   197  }
   198  
   199  func TestLPadRPad(t *testing.T) {
   200  	defer leaktest.AfterTest(t)()
   201  	testCases := []struct {
   202  		padFn    func(string, int, string) (string, error)
   203  		str      string
   204  		length   int
   205  		fill     string
   206  		expected string
   207  	}{
   208  		{lpad, "abc", 1, "xy", "a"},
   209  		{lpad, "abc", 2, "xy", "ab"},
   210  		{lpad, "abc", 3, "xy", "abc"},
   211  		{lpad, "abc", 5, "xy", "xyabc"},
   212  		{lpad, "abc", 6, "xy", "xyxabc"},
   213  		{lpad, "abc", 7, "xy", "xyxyabc"},
   214  		{lpad, "abc", 1, " ", "a"},
   215  		{lpad, "abc", 2, " ", "ab"},
   216  		{lpad, "abc", 3, " ", "abc"},
   217  		{lpad, "abc", 5, " ", "  abc"},
   218  		{lpad, "Hello, 世界", 9, " ", "Hello, 世界"},
   219  		{lpad, "Hello, 世界", 10, " ", " Hello, 世界"},
   220  		{lpad, "Hello", 8, "世界", "世界世Hello"},
   221  		{lpad, "foo", -1, "世界", ""},
   222  		{rpad, "abc", 1, "xy", "a"},
   223  		{rpad, "abc", 2, "xy", "ab"},
   224  		{rpad, "abc", 3, "xy", "abc"},
   225  		{rpad, "abc", 5, "xy", "abcxy"},
   226  		{rpad, "abc", 6, "xy", "abcxyx"},
   227  		{rpad, "abc", 7, "xy", "abcxyxy"},
   228  		{rpad, "abc", 1, " ", "a"},
   229  		{rpad, "abc", 2, " ", "ab"},
   230  		{rpad, "abc", 3, " ", "abc"},
   231  		{rpad, "abc", 5, " ", "abc  "},
   232  		{rpad, "abc", 5, " ", "abc  "},
   233  		{rpad, "Hello, 世界", 9, " ", "Hello, 世界"},
   234  		{rpad, "Hello, 世界", 10, " ", "Hello, 世界 "},
   235  		{rpad, "Hello", 8, "世界", "Hello世界世"},
   236  		{rpad, "foo", -1, "世界", ""},
   237  	}
   238  	for _, tc := range testCases {
   239  		out, err := tc.padFn(tc.str, tc.length, tc.fill)
   240  		if err != nil {
   241  			t.Errorf("Found err %v, expected nil", err)
   242  		}
   243  		if out != tc.expected {
   244  			t.Errorf("expected %s, found %s", tc.expected, out)
   245  		}
   246  	}
   247  }
   248  
   249  func TestExtractTimeSpanFromTimestamp(t *testing.T) {
   250  	defer leaktest.AfterTest(t)()
   251  
   252  	utcPositiveOffset := time.FixedZone("otan happy time", 60*60*4+30*60)
   253  	utcNegativeOffset := time.FixedZone("otan sad time", -60*60*4-30*60)
   254  
   255  	testCases := []struct {
   256  		input    time.Time
   257  		timeSpan string
   258  
   259  		expected      tree.DFloat
   260  		expectedError string
   261  	}{
   262  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "timezone", expected: 0},
   263  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "timezone_hour", expected: 0},
   264  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "timezone_minute", expected: 0},
   265  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "millennia", expected: 3},
   266  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "century", expected: 21},
   267  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "decade", expected: 201},
   268  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "year", expected: 2019},
   269  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "month", expected: 12},
   270  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "day", expected: 11},
   271  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "hour", expected: 0},
   272  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "minute", expected: 14},
   273  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "second", expected: 15.123456},
   274  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "millisecond", expected: 15123.456},
   275  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, time.UTC), timeSpan: "microsecond", expected: 15123456},
   276  
   277  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "timezone", expected: 4*60*60 + 30*60},
   278  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "timezone_hour", expected: 4},
   279  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "timezone_minute", expected: 30},
   280  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "millennia", expected: 3},
   281  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "century", expected: 21},
   282  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "decade", expected: 201},
   283  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "year", expected: 2019},
   284  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "month", expected: 12},
   285  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "day", expected: 11},
   286  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "hour", expected: 0},
   287  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "minute", expected: 14},
   288  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "second", expected: 15.123456},
   289  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "millisecond", expected: 15123.456},
   290  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcPositiveOffset), timeSpan: "microsecond", expected: 15123456},
   291  
   292  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "timezone", expected: -4*60*60 - 30*60},
   293  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "timezone_hour", expected: -4},
   294  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "timezone_minute", expected: -30},
   295  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "millennia", expected: 3},
   296  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "century", expected: 21},
   297  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "decade", expected: 201},
   298  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "year", expected: 2019},
   299  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "month", expected: 12},
   300  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "day", expected: 11},
   301  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "hour", expected: 0},
   302  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "minute", expected: 14},
   303  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "second", expected: 15.123456},
   304  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "millisecond", expected: 15123.456},
   305  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "microsecond", expected: 15123456},
   306  
   307  		{input: time.Date(2019, time.December, 11, 0, 14, 15, 123456000, utcNegativeOffset), timeSpan: "it's numberwang!", expectedError: "unsupported timespan: it's numberwang!"},
   308  	}
   309  
   310  	for _, tc := range testCases {
   311  		t.Run(fmt.Sprintf("%s_%s", tc.timeSpan, tc.input.Format(time.RFC3339)), func(t *testing.T) {
   312  			datum, err := extractTimeSpanFromTimestampTZ(nil, tc.input, tc.timeSpan)
   313  			if tc.expectedError != "" {
   314  				assert.EqualError(t, err, tc.expectedError)
   315  			} else {
   316  				assert.NoError(t, err)
   317  				assert.Equal(t, tc.expected, *(datum.(*tree.DFloat)))
   318  			}
   319  		})
   320  	}
   321  }
   322  
   323  func TestExtractTimeSpanFromTimeTZ(t *testing.T) {
   324  	defer leaktest.AfterTest(t)()
   325  
   326  	testCases := []struct {
   327  		timeTZString  string
   328  		timeSpan      string
   329  		expected      tree.DFloat
   330  		expectedError string
   331  	}{
   332  		{timeTZString: "11:12:13+01:02", timeSpan: "hour", expected: 11},
   333  		{timeTZString: "11:12:13+01:02", timeSpan: "minute", expected: 12},
   334  		{timeTZString: "11:12:13+01:02", timeSpan: "second", expected: 13},
   335  		{timeTZString: "11:12:13.123456+01:02", timeSpan: "millisecond", expected: 13123.456},
   336  		{timeTZString: "11:12:13.123456+01:02", timeSpan: "microsecond", expected: 13123456},
   337  		{timeTZString: "11:12:13+01:02", timeSpan: "timezone", expected: 3720},
   338  		{timeTZString: "11:12:13+01:02", timeSpan: "timezone_hour", expected: 1},
   339  		{timeTZString: "11:12:13+01:02", timeSpan: "timezone_minute", expected: 2},
   340  		{timeTZString: "11:12:13-01:02", timeSpan: "timezone", expected: -3720},
   341  		{timeTZString: "11:12:13-01:02", timeSpan: "timezone_hour", expected: -1},
   342  		{timeTZString: "11:12:13-01:02", timeSpan: "timezone_minute", expected: -2},
   343  		{timeTZString: "11:12:13.5+01:02", timeSpan: "epoch", expected: 36613.5},
   344  		{timeTZString: "11:12:13.5-01:02", timeSpan: "epoch", expected: 44053.5},
   345  
   346  		{timeTZString: "11:12:13-01:02", timeSpan: "epoch2", expectedError: "unsupported timespan: epoch2"},
   347  	}
   348  
   349  	for _, tc := range testCases {
   350  		t.Run(fmt.Sprintf("%s_%s", tc.timeSpan, tc.timeTZString), func(t *testing.T) {
   351  			timeTZ, err := tree.ParseDTimeTZ(nil, tc.timeTZString, time.Microsecond)
   352  			assert.NoError(t, err)
   353  
   354  			datum, err := extractTimeSpanFromTimeTZ(timeTZ, tc.timeSpan)
   355  			if tc.expectedError != "" {
   356  				assert.EqualError(t, err, tc.expectedError)
   357  			} else {
   358  				assert.NoError(t, err)
   359  				assert.Equal(t, tc.expected, *(datum.(*tree.DFloat)))
   360  			}
   361  		})
   362  	}
   363  }
   364  
   365  func TestExtractTimeSpanFromInterval(t *testing.T) {
   366  	defer leaktest.AfterTest(t)()
   367  
   368  	testCases := []struct {
   369  		timeSpan    string
   370  		intervalStr string
   371  		expected    *tree.DFloat
   372  	}{
   373  		{"millennia", "25000 months 1000 days", tree.NewDFloat(2)},
   374  		{"millennia", "-25000 months 1000 days", tree.NewDFloat(-2)},
   375  		{"millennium", "25000 months 1000 days", tree.NewDFloat(2)},
   376  		{"millenniums", "25000 months 1000 days", tree.NewDFloat(2)},
   377  
   378  		{"century", "25000 months 1000 days", tree.NewDFloat(20)},
   379  		{"century", "-25000 months 1000 days", tree.NewDFloat(-20)},
   380  		{"centuries", "25000 months 1000 days", tree.NewDFloat(20)},
   381  
   382  		{"decade", "25000 months 1000 days", tree.NewDFloat(208)},
   383  		{"decade", "-25000 months 1000 days", tree.NewDFloat(-208)},
   384  		{"decades", "25000 months 1000 days", tree.NewDFloat(208)},
   385  
   386  		{"year", "25000 months 1000 days", tree.NewDFloat(2083)},
   387  		{"year", "-25000 months 1000 days", tree.NewDFloat(-2083)},
   388  		{"years", "25000 months 1000 days", tree.NewDFloat(2083)},
   389  
   390  		{"month", "25000 months 1000 days", tree.NewDFloat(4)},
   391  		{"month", "-25000 months 1000 days", tree.NewDFloat(-4)},
   392  		{"months", "25000 months 1000 days", tree.NewDFloat(4)},
   393  
   394  		{"day", "25000 months 1000 days", tree.NewDFloat(1000)},
   395  		{"day", "-25000 months 1000 days", tree.NewDFloat(1000)},
   396  		{"day", "-25000 months -1000 days", tree.NewDFloat(-1000)},
   397  		{"days", "25000 months 1000 days", tree.NewDFloat(1000)},
   398  
   399  		{"hour", "25-1 100:56:01.123456", tree.NewDFloat(100)},
   400  		{"hour", "25-1 -100:56:01.123456", tree.NewDFloat(-100)},
   401  		{"hours", "25-1 100:56:01.123456", tree.NewDFloat(100)},
   402  
   403  		{"minute", "25-1 100:56:01.123456", tree.NewDFloat(56)},
   404  		{"minute", "25-1 -100:56:01.123456", tree.NewDFloat(-56)},
   405  		{"minutes", "25-1 100:56:01.123456", tree.NewDFloat(56)},
   406  
   407  		{"second", "25-1 100:56:01.123456", tree.NewDFloat(1.123456)},
   408  		{"second", "25-1 -100:56:01.123456", tree.NewDFloat(-1.123456)},
   409  		{"seconds", "25-1 100:56:01.123456", tree.NewDFloat(1.123456)},
   410  
   411  		{"millisecond", "25-1 100:56:01.123456", tree.NewDFloat(1123.456)},
   412  		{"millisecond", "25-1 -100:56:01.123456", tree.NewDFloat(-1123.456)},
   413  		{"milliseconds", "25-1 100:56:01.123456", tree.NewDFloat(1123.456)},
   414  
   415  		{"microsecond", "25-1 100:56:01.123456", tree.NewDFloat(1123456)},
   416  		{"microsecond", "25-1 -100:56:01.123456", tree.NewDFloat(-1123456)},
   417  		{"microseconds", "25-1 100:56:01.123456", tree.NewDFloat(1123456)},
   418  
   419  		{"epoch", "25-1 100:56:01.123456", tree.NewDFloat(791895361.123456)},
   420  		{"epoch", "25-1 -100:56:01.123456", tree.NewDFloat(791168638.876544)},
   421  	}
   422  
   423  	for _, tc := range testCases {
   424  		t.Run(fmt.Sprintf("%s as %s", tc.intervalStr, tc.timeSpan), func(t *testing.T) {
   425  			interval, err := tree.ParseDInterval(tc.intervalStr)
   426  			assert.NoError(t, err)
   427  
   428  			d, err := extractTimeSpanFromInterval(interval, tc.timeSpan)
   429  			assert.NoError(t, err)
   430  
   431  			assert.Equal(t, *tc.expected, *(d.(*tree.DFloat)))
   432  		})
   433  	}
   434  }
   435  
   436  func TestTruncateTimestamp(t *testing.T) {
   437  	defer leaktest.AfterTest(t)()
   438  
   439  	loc, err := timeutil.LoadLocation("Australia/Sydney")
   440  	require.NoError(t, err)
   441  
   442  	testCases := []struct {
   443  		fromTime time.Time
   444  		timeSpan string
   445  		expected *tree.DTimestampTZ
   446  	}{
   447  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "millennium", tree.MustMakeDTimestampTZ(time.Date(2001, time.January, 1, 0, 0, 0, 0, loc), time.Microsecond)},
   448  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "century", tree.MustMakeDTimestampTZ(time.Date(2101, time.January, 1, 0, 0, 0, 0, loc), time.Microsecond)},
   449  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "decade", tree.MustMakeDTimestampTZ(time.Date(2110, time.January, 1, 0, 0, 0, 0, loc), time.Microsecond)},
   450  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "year", tree.MustMakeDTimestampTZ(time.Date(2118, time.January, 1, 0, 0, 0, 0, loc), time.Microsecond)},
   451  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "quarter", tree.MustMakeDTimestampTZ(time.Date(2118, time.January, 1, 0, 0, 0, 0, loc), time.Microsecond)},
   452  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "month", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 1, 0, 0, 0, 0, loc), time.Microsecond)},
   453  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "day", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 11, 0, 0, 0, 0, loc), time.Microsecond)},
   454  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "week", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 7, 0, 0, 0, 0, loc), time.Microsecond)},
   455  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "hour", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 11, 5, 0, 0, 0, loc), time.Microsecond)},
   456  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "second", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 11, 5, 6, 7, 0, loc), time.Microsecond)},
   457  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "millisecond", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 11, 5, 6, 7, 80000000, loc), time.Microsecond)},
   458  		{time.Date(2118, time.March, 11, 5, 6, 7, 80009001, loc), "microsecond", tree.MustMakeDTimestampTZ(time.Date(2118, time.March, 11, 5, 6, 7, 80009000, loc), time.Microsecond)},
   459  
   460  		// Test Monday and Sunday boundaries.
   461  		{time.Date(2019, time.November, 11, 5, 6, 7, 80009001, loc), "week", tree.MustMakeDTimestampTZ(time.Date(2019, time.November, 11, 0, 0, 0, 0, loc), time.Microsecond)},
   462  		{time.Date(2019, time.November, 10, 5, 6, 7, 80009001, loc), "week", tree.MustMakeDTimestampTZ(time.Date(2019, time.November, 4, 0, 0, 0, 0, loc), time.Microsecond)},
   463  	}
   464  
   465  	for _, tc := range testCases {
   466  		t.Run(tc.timeSpan, func(t *testing.T) {
   467  			result, err := truncateTimestamp(nil, tc.fromTime, tc.timeSpan)
   468  			require.NoError(t, err)
   469  			assert.Equal(t, tc.expected, result)
   470  		})
   471  	}
   472  }