vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/queryprojection_test.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package operators
    18  
    19  import (
    20  	"testing"
    21  
    22  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    23  	"vitess.io/vitess/go/vt/vtgate/semantics"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/vt/sqlparser"
    30  )
    31  
    32  func TestQP(t *testing.T) {
    33  	tcases := []struct {
    34  		sql string
    35  
    36  		expErr   string
    37  		expOrder []OrderBy
    38  	}{
    39  		{
    40  			sql: "select * from user",
    41  		},
    42  		{
    43  			sql: "select 1, count(1) from user",
    44  		},
    45  		{
    46  			sql: "select max(id) from user",
    47  		},
    48  		{
    49  			sql: "select 1, count(1) from user order by 1",
    50  			expOrder: []OrderBy{
    51  				{Inner: &sqlparser.Order{Expr: sqlparser.NewIntLiteral("1")}, WeightStrExpr: sqlparser.NewIntLiteral("1")},
    52  			},
    53  		},
    54  		{
    55  			sql: "select id from user order by col, id, 1",
    56  			expOrder: []OrderBy{
    57  				{Inner: &sqlparser.Order{Expr: sqlparser.NewColName("col")}, WeightStrExpr: sqlparser.NewColName("col")},
    58  				{Inner: &sqlparser.Order{Expr: sqlparser.NewColName("id")}, WeightStrExpr: sqlparser.NewColName("id")},
    59  				{Inner: &sqlparser.Order{Expr: sqlparser.NewColName("id")}, WeightStrExpr: sqlparser.NewColName("id")},
    60  			},
    61  		},
    62  		{
    63  			sql: "SELECT CONCAT(last_name,', ',first_name) AS full_name FROM mytable ORDER BY full_name", // alias in order not supported
    64  			expOrder: []OrderBy{
    65  				{
    66  					Inner: &sqlparser.Order{Expr: sqlparser.NewColName("full_name")},
    67  					WeightStrExpr: &sqlparser.FuncExpr{
    68  						Name: sqlparser.NewIdentifierCI("CONCAT"),
    69  						Exprs: sqlparser.SelectExprs{
    70  							&sqlparser.AliasedExpr{Expr: sqlparser.NewColName("last_name")},
    71  							&sqlparser.AliasedExpr{Expr: sqlparser.NewStrLiteral(", ")},
    72  							&sqlparser.AliasedExpr{Expr: sqlparser.NewColName("first_name")},
    73  						},
    74  					},
    75  				},
    76  			},
    77  		}, {
    78  			sql:    "select count(*) b from user group by b",
    79  			expErr: "cannot group on 'count(*)'",
    80  		},
    81  	}
    82  	ctx := &plancontext.PlanningContext{SemTable: semantics.EmptySemTable()}
    83  	for _, tcase := range tcases {
    84  		t.Run(tcase.sql, func(t *testing.T) {
    85  			stmt, err := sqlparser.Parse(tcase.sql)
    86  			require.NoError(t, err)
    87  
    88  			sel := stmt.(*sqlparser.Select)
    89  			_, err = semantics.Analyze(sel, "", &semantics.FakeSI{})
    90  			require.NoError(t, err)
    91  
    92  			qp, err := CreateQPFromSelect(ctx, sel)
    93  			if tcase.expErr != "" {
    94  				require.Error(t, err)
    95  				require.Contains(t, err.Error(), tcase.expErr)
    96  			} else {
    97  				require.NoError(t, err)
    98  				assert.Equal(t, len(sel.SelectExprs), len(qp.SelectExprs))
    99  				require.Equal(t, len(tcase.expOrder), len(qp.OrderExprs), "not enough order expressions in QP")
   100  				for index, expOrder := range tcase.expOrder {
   101  					assert.True(t, sqlparser.Equals.SQLNode(expOrder.Inner, qp.OrderExprs[index].Inner), "want: %+v, got %+v", sqlparser.String(expOrder.Inner), sqlparser.String(qp.OrderExprs[index].Inner))
   102  					assert.True(t, sqlparser.Equals.SQLNode(expOrder.WeightStrExpr, qp.OrderExprs[index].WeightStrExpr), "want: %v, got %v", sqlparser.String(expOrder.WeightStrExpr), sqlparser.String(qp.OrderExprs[index].WeightStrExpr))
   103  				}
   104  			}
   105  		})
   106  	}
   107  }
   108  
   109  func TestQPSimplifiedExpr(t *testing.T) {
   110  	testCases := []struct {
   111  		query, expected string
   112  	}{
   113  		{
   114  			query: "select intcol, count(*) from user group by 1",
   115  			expected: `
   116  {
   117    "Select": [
   118      "intcol",
   119      "aggr: count(*)"
   120    ],
   121    "Grouping": [
   122      "intcol"
   123    ],
   124    "OrderBy": [],
   125    "Distinct": false
   126  }`,
   127  		},
   128  		{
   129  			query: "select intcol, textcol from user order by 1, textcol",
   130  			expected: `
   131  {
   132    "Select": [
   133      "intcol",
   134      "textcol"
   135    ],
   136    "Grouping": [],
   137    "OrderBy": [
   138      "intcol asc",
   139      "textcol asc"
   140    ],
   141    "Distinct": false
   142  }`,
   143  		},
   144  		{
   145  			query: "select intcol, textcol, count(id) from user group by intcol, textcol, extracol order by 2 desc",
   146  			expected: `
   147  {
   148    "Select": [
   149      "intcol",
   150      "textcol",
   151      "aggr: count(id)"
   152    ],
   153    "Grouping": [
   154      "intcol",
   155      "textcol",
   156      "extracol"
   157    ],
   158    "OrderBy": [
   159      "textcol desc"
   160    ],
   161    "Distinct": false
   162  }`,
   163  		},
   164  		{
   165  			query: "select distinct col1, col2 from user group by col1, col2",
   166  			expected: `
   167  {
   168    "Select": [
   169      "col1",
   170      "col2"
   171    ],
   172    "Grouping": [],
   173    "OrderBy": [],
   174    "Distinct": true
   175  }`,
   176  		},
   177  		{
   178  			query: "select distinct count(*) from user",
   179  			expected: `
   180  {
   181    "Select": [
   182      "aggr: count(*)"
   183    ],
   184    "Grouping": [],
   185    "OrderBy": [],
   186    "Distinct": false
   187  }`,
   188  		},
   189  	}
   190  
   191  	for _, tc := range testCases {
   192  		t.Run(tc.query, func(t *testing.T) {
   193  			ast, err := sqlparser.Parse(tc.query)
   194  			require.NoError(t, err)
   195  			sel := ast.(*sqlparser.Select)
   196  			_, err = semantics.Analyze(sel, "", &semantics.FakeSI{})
   197  			require.NoError(t, err)
   198  			ctx := &plancontext.PlanningContext{SemTable: semantics.EmptySemTable()}
   199  			qp, err := CreateQPFromSelect(ctx, sel)
   200  			require.NoError(t, err)
   201  			require.Equal(t, tc.expected[1:], qp.toString())
   202  		})
   203  	}
   204  }
   205  
   206  func TestCompareRefInt(t *testing.T) {
   207  	one := 1
   208  	two := 2
   209  	tests := []struct {
   210  		name string
   211  		a    *int
   212  		b    *int
   213  		want bool
   214  	}{
   215  		{
   216  			name: "1<2",
   217  			a:    &one,
   218  			b:    &two,
   219  			want: true,
   220  		}, {
   221  			name: "2<1",
   222  			a:    &two,
   223  			b:    &one,
   224  			want: false,
   225  		}, {
   226  			name: "2<nil",
   227  			a:    &two,
   228  			b:    nil,
   229  			want: true,
   230  		}, {
   231  			name: "nil<1",
   232  			a:    nil,
   233  			b:    &one,
   234  			want: false,
   235  		}, {
   236  			name: "nil<nil",
   237  			a:    nil,
   238  			b:    nil,
   239  			want: false,
   240  		},
   241  	}
   242  	for _, tt := range tests {
   243  		t.Run(tt.name, func(t *testing.T) {
   244  			require.Equal(t, tt.want, CompareRefInt(tt.a, tt.b))
   245  		})
   246  	}
   247  }