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 }