github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/colexec/table_function/generate_series_test.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package table_function
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    21  	"github.com/matrixorigin/matrixone/pkg/container/types"
    22  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    23  	"github.com/matrixorigin/matrixone/pkg/logutil"
    24  	plan2 "github.com/matrixorigin/matrixone/pkg/pb/plan"
    25  	"github.com/matrixorigin/matrixone/pkg/sql/plan"
    26  	"github.com/matrixorigin/matrixone/pkg/testutil"
    27  	"github.com/stretchr/testify/require"
    28  	"math"
    29  	"strings"
    30  	"testing"
    31  )
    32  
    33  type Kase[T int32 | int64] struct {
    34  	start T
    35  	end   T
    36  	step  T
    37  	res   []T
    38  	err   bool
    39  }
    40  
    41  func TestDoGenerateInt32(t *testing.T) {
    42  	kases := []Kase[int32]{
    43  		{
    44  			start: 1,
    45  			end:   10,
    46  			step:  1,
    47  			res:   []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
    48  		},
    49  		{
    50  			start: 1,
    51  			end:   10,
    52  			step:  2,
    53  			res:   []int32{1, 3, 5, 7, 9},
    54  		},
    55  		{
    56  			start: 1,
    57  			end:   10,
    58  			step:  -1,
    59  			res:   []int32{},
    60  		},
    61  		{
    62  			start: 10,
    63  			end:   1,
    64  			step:  -1,
    65  			res:   []int32{10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
    66  		},
    67  		{
    68  			start: 10,
    69  			end:   1,
    70  			step:  -2,
    71  			res:   []int32{10, 8, 6, 4, 2},
    72  		},
    73  		{
    74  			start: 10,
    75  			end:   1,
    76  			step:  1,
    77  			res:   []int32{},
    78  		},
    79  		{
    80  			start: 1,
    81  			end:   10,
    82  			step:  0,
    83  			err:   true,
    84  		},
    85  		{
    86  			start: 1,
    87  			end:   10,
    88  			step:  -1,
    89  			res:   []int32{},
    90  		},
    91  		{
    92  			start: 1,
    93  			end:   1,
    94  			step:  0,
    95  			err:   true,
    96  		},
    97  		{
    98  			start: 1,
    99  			end:   1,
   100  			step:  1,
   101  			res:   []int32{1},
   102  		},
   103  		{
   104  			start: math.MaxInt32 - 1,
   105  			end:   math.MaxInt32,
   106  			step:  1,
   107  			res:   []int32{math.MaxInt32 - 1, math.MaxInt32},
   108  		},
   109  		{
   110  			start: math.MaxInt32,
   111  			end:   math.MaxInt32 - 1,
   112  			step:  -1,
   113  			res:   []int32{math.MaxInt32, math.MaxInt32 - 1},
   114  		},
   115  		{
   116  			start: math.MinInt32,
   117  			end:   math.MinInt32 + 100,
   118  			step:  19,
   119  			res:   []int32{math.MinInt32, math.MinInt32 + 19, math.MinInt32 + 38, math.MinInt32 + 57, math.MinInt32 + 76, math.MinInt32 + 95},
   120  		},
   121  		{
   122  			start: math.MinInt32 + 100,
   123  			end:   math.MinInt32,
   124  			step:  -19,
   125  			res:   []int32{math.MinInt32 + 100, math.MinInt32 + 81, math.MinInt32 + 62, math.MinInt32 + 43, math.MinInt32 + 24, math.MinInt32 + 5},
   126  		},
   127  	}
   128  	for _, kase := range kases {
   129  		res, err := generateInt32(context.TODO(), kase.start, kase.end, kase.step)
   130  		if kase.err {
   131  			require.NotNil(t, err)
   132  			continue
   133  		}
   134  		require.Nil(t, err)
   135  		require.Equal(t, kase.res, res)
   136  	}
   137  }
   138  
   139  func TestDoGenerateInt64(t *testing.T) {
   140  	kases := []Kase[int64]{
   141  		{
   142  			start: 1,
   143  			end:   10,
   144  			step:  1,
   145  			res:   []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
   146  		},
   147  		{
   148  			start: 1,
   149  			end:   10,
   150  			step:  2,
   151  			res:   []int64{1, 3, 5, 7, 9},
   152  		},
   153  		{
   154  			start: 1,
   155  			end:   10,
   156  			step:  -1,
   157  			res:   []int64{},
   158  		},
   159  		{
   160  			start: 10,
   161  			end:   1,
   162  			step:  -1,
   163  			res:   []int64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
   164  		},
   165  		{
   166  			start: 10,
   167  			end:   1,
   168  			step:  -2,
   169  			res:   []int64{10, 8, 6, 4, 2},
   170  		},
   171  		{
   172  			start: 10,
   173  			end:   1,
   174  			step:  1,
   175  			res:   []int64{},
   176  		},
   177  		{
   178  			start: 1,
   179  			end:   10,
   180  			step:  0,
   181  			err:   true,
   182  		},
   183  		{
   184  			start: 1,
   185  			end:   10,
   186  			step:  -1,
   187  			res:   []int64{},
   188  		},
   189  		{
   190  			start: 1,
   191  			end:   1,
   192  			step:  0,
   193  			err:   true,
   194  		},
   195  		{
   196  			start: 1,
   197  			end:   1,
   198  			step:  1,
   199  			res:   []int64{1},
   200  		},
   201  		{
   202  			start: math.MaxInt32 - 1,
   203  			end:   math.MaxInt32,
   204  			step:  1,
   205  			res:   []int64{math.MaxInt32 - 1, math.MaxInt32},
   206  		},
   207  		{
   208  			start: math.MaxInt32,
   209  			end:   math.MaxInt32 - 1,
   210  			step:  -1,
   211  			res:   []int64{math.MaxInt32, math.MaxInt32 - 1},
   212  		},
   213  		{
   214  			start: math.MinInt32,
   215  			end:   math.MinInt32 + 100,
   216  			step:  19,
   217  			res:   []int64{math.MinInt32, math.MinInt32 + 19, math.MinInt32 + 38, math.MinInt32 + 57, math.MinInt32 + 76, math.MinInt32 + 95},
   218  		},
   219  		{
   220  			start: math.MinInt32 + 100,
   221  			end:   math.MinInt32,
   222  			step:  -19,
   223  			res:   []int64{math.MinInt32 + 100, math.MinInt32 + 81, math.MinInt32 + 62, math.MinInt32 + 43, math.MinInt32 + 24, math.MinInt32 + 5},
   224  		},
   225  		// int64
   226  		{
   227  			start: math.MaxInt32,
   228  			end:   math.MaxInt32 + 100,
   229  			step:  19,
   230  			res:   []int64{math.MaxInt32, math.MaxInt32 + 19, math.MaxInt32 + 38, math.MaxInt32 + 57, math.MaxInt32 + 76, math.MaxInt32 + 95},
   231  		},
   232  		{
   233  			start: math.MaxInt32 + 100,
   234  			end:   math.MaxInt32,
   235  			step:  -19,
   236  			res:   []int64{math.MaxInt32 + 100, math.MaxInt32 + 81, math.MaxInt32 + 62, math.MaxInt32 + 43, math.MaxInt32 + 24, math.MaxInt32 + 5},
   237  		},
   238  		{
   239  			start: math.MinInt32,
   240  			end:   math.MinInt32 - 100,
   241  			step:  -19,
   242  			res:   []int64{math.MinInt32, math.MinInt32 - 19, math.MinInt32 - 38, math.MinInt32 - 57, math.MinInt32 - 76, math.MinInt32 - 95},
   243  		},
   244  		{
   245  			start: math.MinInt32 - 100,
   246  			end:   math.MinInt32,
   247  			step:  19,
   248  			res:   []int64{math.MinInt32 - 100, math.MinInt32 - 81, math.MinInt32 - 62, math.MinInt32 - 43, math.MinInt32 - 24, math.MinInt32 - 5},
   249  		},
   250  		{
   251  			start: math.MaxInt64 - 1,
   252  			end:   math.MaxInt64,
   253  			step:  1,
   254  			res:   []int64{math.MaxInt64 - 1, math.MaxInt64},
   255  		},
   256  		{
   257  			start: math.MaxInt64,
   258  			end:   math.MaxInt64 - 1,
   259  			step:  -1,
   260  			res:   []int64{math.MaxInt64, math.MaxInt64 - 1},
   261  		},
   262  		{
   263  			start: math.MaxInt64 - 100,
   264  			end:   math.MaxInt64,
   265  			step:  19,
   266  			res:   []int64{math.MaxInt64 - 100, math.MaxInt64 - 81, math.MaxInt64 - 62, math.MaxInt64 - 43, math.MaxInt64 - 24, math.MaxInt64 - 5},
   267  		},
   268  		{
   269  			start: math.MaxInt64,
   270  			end:   math.MaxInt64 - 100,
   271  			step:  -19,
   272  			res:   []int64{math.MaxInt64, math.MaxInt64 - 19, math.MaxInt64 - 38, math.MaxInt64 - 57, math.MaxInt64 - 76, math.MaxInt64 - 95},
   273  		},
   274  		{
   275  			start: math.MinInt64,
   276  			end:   math.MinInt64 + 100,
   277  			step:  19,
   278  			res:   []int64{math.MinInt64, math.MinInt64 + 19, math.MinInt64 + 38, math.MinInt64 + 57, math.MinInt64 + 76, math.MinInt64 + 95},
   279  		},
   280  		{
   281  			start: math.MinInt64 + 100,
   282  			end:   math.MinInt64,
   283  			step:  -19,
   284  			res:   []int64{math.MinInt64 + 100, math.MinInt64 + 81, math.MinInt64 + 62, math.MinInt64 + 43, math.MinInt64 + 24, math.MinInt64 + 5},
   285  		},
   286  	}
   287  	for _, kase := range kases {
   288  		res, err := generateInt64(context.TODO(), kase.start, kase.end, kase.step)
   289  		if kase.err {
   290  			require.NotNil(t, err)
   291  			continue
   292  		}
   293  		require.Nil(t, err)
   294  		require.Equal(t, kase.res, res)
   295  	}
   296  }
   297  
   298  func TestGenerateTimestamp(t *testing.T) {
   299  	kases := []struct {
   300  		start string
   301  		end   string
   302  		step  string
   303  		res   []types.Datetime
   304  		err   bool
   305  	}{
   306  		{
   307  			start: "2019-01-01 00:00:00",
   308  			end:   "2019-01-01 00:01:00",
   309  			step:  "30 second",
   310  			res: []types.Datetime{
   311  				transStr2Datetime("2019-01-01 00:00:00"),
   312  				transStr2Datetime("2019-01-01 00:00:30"),
   313  				transStr2Datetime("2019-01-01 00:01:00"),
   314  			},
   315  		},
   316  		{
   317  			start: "2019-01-01 00:01:00",
   318  			end:   "2019-01-01 00:00:00",
   319  			step:  "-30 second",
   320  			res: []types.Datetime{
   321  				transStr2Datetime("2019-01-01 00:01:00"),
   322  				transStr2Datetime("2019-01-01 00:00:30"),
   323  				transStr2Datetime("2019-01-01 00:00:00"),
   324  			},
   325  		},
   326  		{
   327  			start: "2019-01-01 00:00:00",
   328  			end:   "2019-01-01 00:01:00",
   329  			step:  "30 minute",
   330  			res: []types.Datetime{
   331  				transStr2Datetime("2019-01-01 00:00:00"),
   332  			},
   333  		},
   334  		{
   335  			start: "2020-02-29 00:01:00",
   336  			end:   "2021-03-01 00:00:00",
   337  			step:  "1 year",
   338  			res: []types.Datetime{
   339  				transStr2Datetime("2020-02-29 00:01:00"),
   340  				transStr2Datetime("2021-02-28 00:01:00"),
   341  			},
   342  		},
   343  		{
   344  			start: "2020-02-29 00:01:00",
   345  			end:   "2021-03-01 00:00:00",
   346  			step:  "1 month",
   347  			res: []types.Datetime{
   348  				transStr2Datetime("2020-02-29 00:01:00"),
   349  				transStr2Datetime("2020-03-29 00:01:00"),
   350  				transStr2Datetime("2020-04-29 00:01:00"),
   351  				transStr2Datetime("2020-05-29 00:01:00"),
   352  				transStr2Datetime("2020-06-29 00:01:00"),
   353  				transStr2Datetime("2020-07-29 00:01:00"),
   354  				transStr2Datetime("2020-08-29 00:01:00"),
   355  				transStr2Datetime("2020-09-29 00:01:00"),
   356  				transStr2Datetime("2020-10-29 00:01:00"),
   357  				transStr2Datetime("2020-11-29 00:01:00"),
   358  				transStr2Datetime("2020-12-29 00:01:00"),
   359  				transStr2Datetime("2021-01-29 00:01:00"),
   360  				transStr2Datetime("2021-02-28 00:01:00"),
   361  			},
   362  		},
   363  		{
   364  			start: "2020-02-29 00:01:00",
   365  			end:   "2021-03-01 00:00:00",
   366  			step:  "1 year",
   367  			res: []types.Datetime{
   368  				transStr2Datetime("2020-02-29 00:01:00"),
   369  				transStr2Datetime("2021-02-28 00:01:00"),
   370  			},
   371  		},
   372  		{
   373  			start: "2020-02-28 00:01:00",
   374  			end:   "2021-03-01 00:00:00",
   375  			step:  "1 year",
   376  			res: []types.Datetime{
   377  				transStr2Datetime("2020-02-28 00:01:00"),
   378  				transStr2Datetime("2021-02-28 00:01:00"),
   379  			},
   380  		},
   381  	}
   382  	for _, kase := range kases {
   383  		var precision int32
   384  		p1, p2 := getPrecision(kase.start), getPrecision(kase.end)
   385  		if p1 > p2 {
   386  			precision = p1
   387  		} else {
   388  			precision = p2
   389  		}
   390  		start, err := types.ParseDatetime(kase.start, precision)
   391  		require.Nil(t, err)
   392  		end, err := types.ParseDatetime(kase.end, precision)
   393  		require.Nil(t, err)
   394  		res, err := generateDatetime(context.TODO(), start, end, kase.step, precision)
   395  		if kase.err {
   396  			require.NotNil(t, err)
   397  			continue
   398  		}
   399  		require.Nil(t, err)
   400  		require.Equal(t, kase.res, res)
   401  	}
   402  }
   403  
   404  func transStr2Datetime(s string) types.Datetime {
   405  	precision := getPrecision(s)
   406  	t, err := types.ParseDatetime(s, precision)
   407  	if err != nil {
   408  		logutil.Errorf("parse timestamp '%s' failed", s)
   409  	}
   410  	return t
   411  }
   412  
   413  func getPrecision(s string) int32 {
   414  	var precision int32
   415  	ss := strings.Split(s, ".")
   416  	if len(ss) > 1 {
   417  		precision = int32(len(ss[1]))
   418  	}
   419  	return precision
   420  }
   421  
   422  func TestGenerateSeriesString(t *testing.T) {
   423  	generateSeriesString(nil, new(bytes.Buffer))
   424  }
   425  
   426  func TestGenerateSeriesPrepare(t *testing.T) {
   427  	err := generateSeriesPrepare(nil, nil)
   428  	require.Nil(t, err)
   429  }
   430  func TestGenStep(t *testing.T) {
   431  	ctx := context.TODO()
   432  	kase := "10 hour"
   433  	num, tp, err := genStep(ctx, kase)
   434  	require.Nil(t, err)
   435  	require.Equal(t, int64(10), num)
   436  	require.Equal(t, types.Hour, tp)
   437  	kase = "10 houx"
   438  	_, _, err = genStep(ctx, kase)
   439  	require.NotNil(t, err)
   440  	kase = "hour"
   441  	_, _, err = genStep(ctx, kase)
   442  	require.NotNil(t, err)
   443  	kase = "989829829129131939147193 hour"
   444  	_, _, err = genStep(ctx, kase)
   445  	require.NotNil(t, err)
   446  }
   447  
   448  func TestGenerateSeriesCall(t *testing.T) {
   449  	proc := testutil.NewProc()
   450  	beforeCall := proc.Mp().CurrNB()
   451  	arg := &Argument{
   452  		Attrs: []string{"result"},
   453  	}
   454  	proc.SetInputBatch(nil)
   455  	end, err := generateSeriesCall(0, proc, arg)
   456  	require.Nil(t, err)
   457  	require.Equal(t, true, end)
   458  
   459  	arg.Args = makeInt64List(1, 3, 1)
   460  
   461  	bat := makeGenerateSeriesBatch()
   462  	proc.SetInputBatch(bat)
   463  	end, err = generateSeriesCall(0, proc, arg)
   464  	require.Nil(t, err)
   465  	require.Equal(t, false, end)
   466  	require.Equal(t, 3, proc.InputBatch().GetVector(0).Length())
   467  	proc.InputBatch().Clean(proc.Mp())
   468  
   469  	arg.Args = makeDatetimeList("2020-01-01 00:00:00", "2020-01-01 00:00:59", "1 second", 0)
   470  	proc.SetInputBatch(bat)
   471  	end, err = generateSeriesCall(0, proc, arg)
   472  	require.Nil(t, err)
   473  	require.Equal(t, false, end)
   474  	require.Equal(t, 60, proc.InputBatch().GetVector(0).Length())
   475  	proc.InputBatch().Clean(proc.Mp())
   476  
   477  	arg.Args = makeVarcharList("2020-01-01 00:00:00", "2020-01-01 00:00:59", "1 second")
   478  	proc.SetInputBatch(bat)
   479  	end, err = generateSeriesCall(0, proc, arg)
   480  	require.Nil(t, err)
   481  	require.Equal(t, false, end)
   482  	require.Equal(t, 60, proc.InputBatch().GetVector(0).Length())
   483  	proc.InputBatch().Clean(proc.Mp())
   484  
   485  	arg.Args = makeVarcharList("1", "10", "3")
   486  	proc.SetInputBatch(bat)
   487  	end, err = generateSeriesCall(0, proc, arg)
   488  	require.Nil(t, err)
   489  	require.Equal(t, false, end)
   490  	require.Equal(t, 4, proc.InputBatch().GetVector(0).Length())
   491  	proc.InputBatch().Clean(proc.Mp())
   492  
   493  	arg.Args = arg.Args[:2]
   494  	proc.SetInputBatch(bat)
   495  	_, err = generateSeriesCall(0, proc, arg)
   496  	require.NotNil(t, err)
   497  	bat.Clean(proc.Mp())
   498  	require.Equal(t, beforeCall, proc.Mp().CurrNB())
   499  
   500  }
   501  
   502  func makeGenerateSeriesBatch() *batch.Batch {
   503  	bat := batch.NewWithSize(1)
   504  	bat.Vecs[0] = vector.NewConst(types.Type{Oid: types.T_int64}, 1)
   505  	bat.Vecs[0].Col = make([]int64, 1)
   506  	bat.InitZsOne(1)
   507  	return bat
   508  }
   509  
   510  func makeInt64List(start, end, step int64) []*plan.Expr {
   511  	ret := make([]*plan.Expr, 3)
   512  	ret[0] = makeInt64Expr(start)
   513  	ret[1] = makeInt64Expr(end)
   514  	ret[2] = makeInt64Expr(step)
   515  	return ret
   516  }
   517  
   518  func makeDatetimeList(start, end, step string, precision int32) []*plan.Expr {
   519  	ret := make([]*plan.Expr, 3)
   520  	ret[0] = makeDatetimeExpr(start, precision)
   521  	ret[1] = makeDatetimeExpr(end, precision)
   522  	ret[2] = makeVarcharExpr(step)
   523  	return ret
   524  }
   525  func makeVarcharList(start, end, step string) []*plan.Expr {
   526  	ret := make([]*plan.Expr, 3)
   527  	ret[0] = makeVarcharExpr(start)
   528  	ret[1] = makeVarcharExpr(end)
   529  	ret[2] = makeVarcharExpr(step)
   530  	return ret
   531  }
   532  
   533  func makeInt64Expr(val int64) *plan.Expr {
   534  	return &plan.Expr{
   535  		Typ: &plan.Type{
   536  			Id: int32(types.T_int64),
   537  		},
   538  		Expr: &plan2.Expr_C{
   539  			C: &plan.Const{
   540  				Value: &plan2.Const_I64Val{
   541  					I64Val: val,
   542  				},
   543  			},
   544  		},
   545  	}
   546  }
   547  func makeVarcharExpr(val string) *plan.Expr {
   548  	return &plan.Expr{
   549  		Typ: &plan.Type{
   550  			Id: int32(types.T_varchar),
   551  		},
   552  		Expr: &plan2.Expr_C{
   553  			C: &plan.Const{
   554  				Value: &plan2.Const_Sval{
   555  					Sval: val,
   556  				},
   557  			},
   558  		},
   559  	}
   560  }
   561  
   562  func makeDatetimeExpr(s string, p int32) *plan.Expr {
   563  	dt, _ := types.ParseDatetime(s, p)
   564  	return &plan.Expr{
   565  		Typ: &plan.Type{
   566  			Id:        int32(types.T_datetime),
   567  			Precision: p,
   568  		},
   569  		Expr: &plan2.Expr_C{
   570  			C: &plan.Const{
   571  				Value: &plan2.Const_Datetimeval{
   572  					Datetimeval: int64(dt),
   573  				},
   574  			},
   575  		},
   576  	}
   577  }