github.com/dolthub/go-mysql-server@v0.18.0/sql/memo/rel_props_test.go (about)

     1  package memo
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/dolthub/go-mysql-server/sql"
    10  	"github.com/dolthub/go-mysql-server/sql/expression"
    11  	"github.com/dolthub/go-mysql-server/sql/plan"
    12  	"github.com/dolthub/go-mysql-server/sql/types"
    13  )
    14  
    15  func TestPopulateFDs(t *testing.T) {
    16  	// source relations
    17  	tests := []struct {
    18  		name    string
    19  		in      RelExpr
    20  		all     sql.ColSet
    21  		notNull sql.ColSet
    22  		indexes []*Index
    23  		key     sql.ColSet
    24  	}{
    25  		{
    26  			name: "tablescan",
    27  			in: &TableScan{
    28  				sourceBase: &sourceBase{relBase: &relBase{}},
    29  				Table: plan.NewResolvedTable(
    30  					&dummyTable{
    31  						schema: sql.NewPrimaryKeySchema(sql.Schema{
    32  							{Name: "x", Source: "t", Type: types.Int64, Nullable: false},
    33  							{Name: "y", Source: "t", Type: types.Int64, Nullable: false},
    34  							{Name: "z", Source: "t", Type: types.Int64, Nullable: false},
    35  						}, 1, 0),
    36  					}, nil, nil).WithId(1).WithColumns(sql.NewColSet(1, 2, 3)),
    37  			},
    38  			all:     sql.NewColSet(1, 2, 3),
    39  			notNull: sql.NewColSet(1, 2, 3),
    40  			indexes: []*Index{
    41  				{
    42  					order: []sql.ColumnId{2, 1},
    43  					set:   sql.NewColSet(1, 2),
    44  				},
    45  			},
    46  			key: sql.NewColSet(1, 2),
    47  		},
    48  		{
    49  			name: "table alias",
    50  			in: &TableAlias{
    51  				sourceBase: &sourceBase{relBase: &relBase{}},
    52  				Table: plan.NewTableAlias("tab", plan.NewResolvedTable(
    53  					&dummyTable{
    54  						schema: sql.NewPrimaryKeySchema(sql.Schema{
    55  							{Name: "x", Source: "t", Type: types.Int64, Nullable: false},
    56  							{Name: "y", Source: "t", Type: types.Int64, Nullable: false},
    57  							{Name: "z", Source: "t", Type: types.Int64, Nullable: false},
    58  						}, 0, 1, 2),
    59  					}, nil, nil).WithId(1).WithColumns(sql.NewColSet(1, 2, 3))),
    60  			},
    61  			all:     sql.NewColSet(1, 2, 3),
    62  			notNull: sql.NewColSet(1, 2, 3),
    63  			indexes: []*Index{
    64  				{
    65  					order: []sql.ColumnId{1, 2, 3},
    66  					set:   sql.NewColSet(1, 2, 3),
    67  				},
    68  			},
    69  			key: sql.NewColSet(1, 2, 3),
    70  		},
    71  		{
    72  			name: "empty table",
    73  			in: &EmptyTable{
    74  				sourceBase: &sourceBase{relBase: &relBase{}},
    75  				Table: plan.NewEmptyTableWithSchema(
    76  					sql.Schema{
    77  						{Name: "x", Source: "t", Type: types.Int64, Nullable: false},
    78  						{Name: "y", Source: "t", Type: types.Int64, Nullable: false},
    79  						{Name: "z", Source: "t", Type: types.Int64, Nullable: false},
    80  					}).(*plan.EmptyTable).WithId(1).WithColumns(sql.NewColSet(1, 2, 3)).(*plan.EmptyTable),
    81  			},
    82  			// planning ignores empty tables for now
    83  			all:     sql.NewColSet(),
    84  			notNull: sql.NewColSet(),
    85  		},
    86  		{
    87  			name: "max1Row",
    88  			in: &Max1Row{
    89  				relBase: &relBase{},
    90  				Child: newExprGroup(NewMemo(nil, nil, nil, 0, nil), 0, &TableScan{
    91  					sourceBase: &sourceBase{relBase: &relBase{}},
    92  					Table: plan.NewResolvedTable(
    93  						&dummyTable{
    94  							schema: sql.NewPrimaryKeySchema(sql.Schema{
    95  								{Name: "x", Source: "t", Type: types.Int64, Nullable: false},
    96  								{Name: "y", Source: "t", Type: types.Int64, Nullable: false},
    97  								{Name: "z", Source: "t", Type: types.Int64, Nullable: false},
    98  							}),
    99  						}, nil, nil).WithId(1).WithColumns(sql.NewColSet(1, 2, 3)),
   100  				},
   101  				),
   102  			},
   103  			all:     sql.NewColSet(1, 2, 3),
   104  			notNull: sql.NewColSet(1, 2, 3),
   105  			key:     sql.ColSet{},
   106  		},
   107  		{
   108  			name: "values",
   109  			in: &Values{
   110  				sourceBase: &sourceBase{relBase: &relBase{}},
   111  				Table:      plan.NewValueDerivedTable(plan.NewValues([][]sql.Expression{{expression.NewLiteral(1, types.Int64)}}), "values").WithId(1).WithColumns(sql.NewColSet(1)).(*plan.ValueDerivedTable),
   112  			},
   113  			all:     sql.NewColSet(1),
   114  			notNull: sql.NewColSet(1),
   115  		},
   116  	}
   117  
   118  	for _, tt := range tests {
   119  		t.Run(tt.name, func(t *testing.T) {
   120  			tt.in.SetGroup(&ExprGroup{First: tt.in, m: NewMemo(nil, nil, nil, 0, nil)})
   121  			props := newRelProps(tt.in)
   122  			require.Equal(t, tt.all, props.fds.All())
   123  			require.Equal(t, tt.notNull, props.fds.NotNull())
   124  
   125  			cmp, ok := props.fds.StrictKey()
   126  			if !tt.key.Empty() {
   127  				require.True(t, ok)
   128  				require.Equal(t, tt.key, cmp)
   129  			} else if ok {
   130  				require.True(t, props.fds.HasMax1Row())
   131  			}
   132  
   133  			if src, ok := tt.in.(SourceRel); ok {
   134  				cmpIdx := src.Indexes()
   135  				require.Equal(t, len(tt.indexes), len(cmpIdx))
   136  				for i, ii := range tt.indexes {
   137  					cmp := cmpIdx[i]
   138  					require.Equal(t, ii.Cols(), cmp.Cols())
   139  					require.Equal(t, ii.ColSet(), cmp.ColSet())
   140  				}
   141  			}
   142  		})
   143  	}
   144  }
   145  
   146  type dummyTable struct {
   147  	schema sql.PrimaryKeySchema
   148  }
   149  
   150  var _ sql.Table = (*dummyTable)(nil)
   151  var _ sql.PrimaryKeyTable = (*dummyTable)(nil)
   152  var _ sql.IndexAddressable = (*dummyTable)(nil)
   153  
   154  func (t *dummyTable) IndexedAccess(sql.IndexLookup) sql.IndexedTable {
   155  	panic("implement me")
   156  }
   157  
   158  func (t *dummyTable) PreciseMatch() bool {
   159  	return true
   160  }
   161  
   162  func (t *dummyTable) GetIndexes(*sql.Context) ([]sql.Index, error) {
   163  	var exprs []string
   164  	for _, i := range t.schema.PkOrdinals {
   165  		exprs = append(exprs, fmt.Sprintf("%s.%s", t.Name(), t.schema.Schema[i].Name))
   166  	}
   167  	return []sql.Index{dummyIndex{cols: exprs}}, nil
   168  }
   169  
   170  func (t *dummyTable) PrimaryKeySchema() sql.PrimaryKeySchema {
   171  	return t.schema
   172  }
   173  
   174  func (t *dummyTable) Name() string { return "dummy" }
   175  
   176  func (t *dummyTable) String() string {
   177  	return "name"
   178  }
   179  
   180  func (*dummyTable) Insert(*sql.Context, sql.Row) error {
   181  	panic("not implemented")
   182  }
   183  
   184  func (t *dummyTable) Schema() sql.Schema { return t.schema.Schema }
   185  
   186  func (t *dummyTable) Collation() sql.CollationID { return sql.Collation_Default }
   187  
   188  func (t *dummyTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) {
   189  	panic("not implemented")
   190  }
   191  
   192  func (t *dummyTable) PartitionRows(ctx *sql.Context, partition sql.Partition) (sql.RowIter, error) {
   193  	panic("not implemented")
   194  }
   195  
   196  type dummyIndex struct {
   197  	cols []string
   198  }
   199  
   200  func (dummyIndex) CanSupport(...sql.Range) bool {
   201  	return true
   202  }
   203  
   204  func (dummyIndex) ID() string {
   205  	return "test_index"
   206  }
   207  
   208  func (dummyIndex) Database() string {
   209  	return "database"
   210  }
   211  
   212  func (dummyIndex) Table() string {
   213  	return "table"
   214  }
   215  
   216  func (i dummyIndex) Expressions() []string {
   217  	return i.cols
   218  }
   219  
   220  func (dummyIndex) IsUnique() bool {
   221  	return true
   222  }
   223  
   224  func (dummyIndex) IsSpatial() bool {
   225  	return false
   226  }
   227  
   228  func (dummyIndex) IsFullText() bool {
   229  	return false
   230  }
   231  
   232  func (dummyIndex) Comment() string {
   233  	return ""
   234  }
   235  
   236  func (dummyIndex) IndexType() string {
   237  	return "FAKE"
   238  }
   239  
   240  func (dummyIndex) IsGenerated() bool {
   241  	return false
   242  }
   243  
   244  func (i dummyIndex) ColumnExpressionTypes() []sql.ColumnExpressionType {
   245  	es := i.Expressions()
   246  	res := make([]sql.ColumnExpressionType, len(es))
   247  	for i := range es {
   248  		res[i] = sql.ColumnExpressionType{Expression: es[i], Type: types.Int8}
   249  	}
   250  	return res
   251  }
   252  
   253  func (dummyIndex) PrefixLengths() []uint16 {
   254  	return nil
   255  }
   256  
   257  var _ sql.Index = dummyIndex{}