github.com/dolthub/go-mysql-server@v0.18.0/memory/sequence_table.go (about)

     1  package memory
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/dolthub/go-mysql-server/sql"
     9  	"github.com/dolthub/go-mysql-server/sql/expression"
    10  	"github.com/dolthub/go-mysql-server/sql/types"
    11  )
    12  
    13  var _ sql.TableFunction = IntSequenceTable{}
    14  var _ sql.CollationCoercible = IntSequenceTable{}
    15  var _ sql.ExecSourceRel = IntSequenceTable{}
    16  var _ sql.IndexAddressable = IntSequenceTable{}
    17  var _ sql.IndexedTable = IntSequenceTable{}
    18  var _ sql.TableNode = IntSequenceTable{}
    19  
    20  // IntSequenceTable a simple table function that returns a sequence
    21  // of integers.
    22  type IntSequenceTable struct {
    23  	db   sql.Database
    24  	name string
    25  	Len  int64
    26  }
    27  
    28  func (s IntSequenceTable) UnderlyingTable() sql.Table {
    29  	return s
    30  }
    31  
    32  func (s IntSequenceTable) NewInstance(_ *sql.Context, db sql.Database, args []sql.Expression) (sql.Node, error) {
    33  	if len(args) != 2 {
    34  		return nil, fmt.Errorf("sequence table expects 2 arguments: (name, len)")
    35  	}
    36  	nameExp, ok := args[0].(*expression.Literal)
    37  	if !ok {
    38  		return nil, fmt.Errorf("sequence table expects arguments to be literal expressions")
    39  	}
    40  	name, ok := nameExp.Value().(string)
    41  	if !ok {
    42  		return nil, fmt.Errorf("sequence table expects 1st argument to be column name")
    43  	}
    44  	lenExp, ok := args[1].(*expression.Literal)
    45  	if !ok {
    46  		return nil, fmt.Errorf("sequence table expects arguments to be literal expressions")
    47  	}
    48  	length, _, err := types.Int64.Convert(lenExp.Value())
    49  	if !ok {
    50  		return nil, fmt.Errorf("%w; sequence table expects 2nd argument to be a sequence length integer", err)
    51  	}
    52  	return IntSequenceTable{db: db, name: name, Len: length.(int64)}, nil
    53  }
    54  
    55  func (s IntSequenceTable) Resolved() bool {
    56  	return true
    57  }
    58  
    59  func (s IntSequenceTable) IsReadOnly() bool {
    60  	return true
    61  }
    62  
    63  func (s IntSequenceTable) String() string {
    64  	return fmt.Sprintf("sequence(%s, %d)", s.name, s.Len)
    65  }
    66  
    67  func (s IntSequenceTable) DebugString() string {
    68  	pr := sql.NewTreePrinter()
    69  	_ = pr.WriteNode("sequence")
    70  	children := []string{
    71  		fmt.Sprintf("name: %s", s.name),
    72  		fmt.Sprintf("len: %d", s.Len),
    73  	}
    74  	_ = pr.WriteChildren(children...)
    75  	return pr.String()
    76  }
    77  
    78  func (s IntSequenceTable) Schema() sql.Schema {
    79  	schema := []*sql.Column{
    80  		{
    81  			DatabaseSource: s.db.Name(),
    82  			Source:         s.Name(),
    83  			Name:           s.name,
    84  			Type:           types.Int64,
    85  		},
    86  	}
    87  
    88  	return schema
    89  }
    90  
    91  func (s IntSequenceTable) Children() []sql.Node {
    92  	return []sql.Node{}
    93  }
    94  
    95  func (s IntSequenceTable) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) {
    96  	rowIter := &SequenceTableFnRowIter{i: 0, n: s.Len}
    97  	return rowIter, nil
    98  }
    99  
   100  func (s IntSequenceTable) WithChildren(_ ...sql.Node) (sql.Node, error) {
   101  	return s, nil
   102  }
   103  
   104  func (s IntSequenceTable) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool {
   105  	return true
   106  }
   107  
   108  // CollationCoercibility implements the interface sql.CollationCoercible.
   109  func (IntSequenceTable) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   110  	return sql.Collation_binary, 5
   111  }
   112  
   113  // Collation implements the sql.Table interface.
   114  func (IntSequenceTable) Collation() sql.CollationID {
   115  	return sql.Collation_Default
   116  }
   117  
   118  func (s IntSequenceTable) Expressions() []sql.Expression {
   119  	return []sql.Expression{}
   120  }
   121  
   122  func (s IntSequenceTable) WithExpressions(e ...sql.Expression) (sql.Node, error) {
   123  	return s, nil
   124  }
   125  
   126  func (s IntSequenceTable) Database() sql.Database {
   127  	return s.db
   128  }
   129  
   130  func (s IntSequenceTable) WithDatabase(_ sql.Database) (sql.Node, error) {
   131  	return s, nil
   132  }
   133  
   134  func (s IntSequenceTable) Name() string {
   135  	return "sequence_table"
   136  }
   137  
   138  func (s IntSequenceTable) Description() string {
   139  	return "sequence"
   140  }
   141  
   142  var _ sql.RowIter = (*SequenceTableFnRowIter)(nil)
   143  
   144  type SequenceTableFnRowIter struct {
   145  	n int64
   146  	i int64
   147  }
   148  
   149  func (i *SequenceTableFnRowIter) Next(_ *sql.Context) (sql.Row, error) {
   150  	if i.i >= i.n {
   151  		return nil, io.EOF
   152  	}
   153  	ret := sql.Row{i.i}
   154  	i.i++
   155  	return ret, nil
   156  }
   157  
   158  func (i *SequenceTableFnRowIter) Close(_ *sql.Context) error {
   159  	return nil
   160  }
   161  
   162  var _ sql.Partition = (*sequencePartition)(nil)
   163  
   164  type sequencePartition struct {
   165  	min, max int64
   166  }
   167  
   168  func (s sequencePartition) Key() []byte {
   169  	return binary.LittleEndian.AppendUint64(binary.LittleEndian.AppendUint64(nil, uint64(s.min)), uint64(s.max))
   170  }
   171  
   172  // Partitions is a sql.Table interface function that returns a partition of the data. This data has a single partition.
   173  func (s IntSequenceTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) {
   174  	return sql.PartitionsToPartitionIter(&sequencePartition{min: 0, max: int64(s.Len) - 1}), nil
   175  }
   176  
   177  // PartitionRows is a sql.Table interface function that takes a partition and returns all rows in that partition.
   178  // This table has a partition for just schema changes, one for just data changes, and one for both.
   179  func (s IntSequenceTable) PartitionRows(ctx *sql.Context, partition sql.Partition) (sql.RowIter, error) {
   180  	sp, ok := partition.(*sequencePartition)
   181  	if !ok {
   182  		return &SequenceTableFnRowIter{i: 0, n: s.Len}, nil
   183  	}
   184  	min := int64(0)
   185  	if sp.min > min {
   186  		min = sp.min
   187  	}
   188  	max := int64(s.Len) - 1
   189  	if sp.max < max {
   190  		max = sp.max
   191  	}
   192  
   193  	return &SequenceTableFnRowIter{i: min, n: max + 1}, nil
   194  }
   195  
   196  // LookupPartitions is a sql.IndexedTable interface function that takes an index lookup and returns the set of corresponding partitions.
   197  func (s IntSequenceTable) LookupPartitions(context *sql.Context, lookup sql.IndexLookup) (sql.PartitionIter, error) {
   198  	lowerBound := lookup.Ranges[0][0].LowerBound
   199  	below, ok := lowerBound.(sql.Below)
   200  	if !ok {
   201  		return s.Partitions(context)
   202  	}
   203  	upperBound := lookup.Ranges[0][0].UpperBound
   204  	above, ok := upperBound.(sql.Above)
   205  	if !ok {
   206  		return s.Partitions(context)
   207  	}
   208  	min, _, err := s.Schema()[0].Type.Convert(below.Key)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	max, _, err := s.Schema()[0].Type.Convert(above.Key)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	return sql.PartitionsToPartitionIter(&sequencePartition{min: min.(int64), max: max.(int64)}), nil
   217  }
   218  
   219  func (s IntSequenceTable) IndexedAccess(lookup sql.IndexLookup) sql.IndexedTable {
   220  	return s
   221  }
   222  
   223  func (s IntSequenceTable) PreciseMatch() bool {
   224  	return true
   225  }
   226  
   227  func (s IntSequenceTable) GetIndexes(ctx *sql.Context) ([]sql.Index, error) {
   228  	return []sql.Index{
   229  		&Index{
   230  			DB:         s.db.Name(),
   231  			DriverName: "",
   232  			Tbl:        nil,
   233  			TableName:  s.Name(),
   234  			Exprs: []sql.Expression{
   235  				expression.NewGetFieldWithTable(0, 0, types.Int64, s.db.Name(), s.Name(), s.name, false),
   236  			},
   237  			Name:         s.name,
   238  			Unique:       true,
   239  			Spatial:      false,
   240  			Fulltext:     false,
   241  			CommentStr:   "",
   242  			PrefixLens:   nil,
   243  			fulltextInfo: fulltextInfo{},
   244  		},
   245  	}, nil
   246  }