github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/merge/fulltext_table.go (about) 1 // Copyright 2023 Dolthub, Inc. 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 merge 16 17 import ( 18 "fmt" 19 "io" 20 21 "github.com/dolthub/go-mysql-server/memory" 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/dolthub/go-mysql-server/sql/fulltext" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 26 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 27 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 28 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 29 "github.com/dolthub/dolt/go/store/pool" 30 "github.com/dolthub/dolt/go/store/prolly/tree" 31 "github.com/dolthub/dolt/go/store/val" 32 ) 33 34 var sharePool = pool.NewBuffPool() 35 36 type fulltextTable struct { 37 GMSTable *memory.Table 38 Table *doltdb.Table 39 Sch schema.Schema 40 SqlSch sql.Schema 41 } 42 43 var _ fulltext.EditableTable = (*fulltextTable)(nil) 44 45 // createFulltextTable creates an in-memory Full-Text table from the given table name on the given root. This table will 46 // be used to read/write data from/to the underlying Dolt table. 47 func createFulltextTable(ctx *sql.Context, name string, root doltdb.RootValue) (*fulltextTable, error) { 48 tbl, ok, err := root.GetTable(ctx, doltdb.TableName{Name: name}) 49 if err != nil { 50 return nil, err 51 } 52 if !ok { 53 return nil, fmt.Errorf("attempted to load Full-Text table `%s` during Full-Text merge but it could not be found", name) 54 } 55 sch, err := tbl.GetSchema(ctx) 56 if err != nil { 57 return nil, err 58 } 59 sqlSch, err := sqlutil.FromDoltSchema("", name, sch) 60 if err != nil { 61 return nil, err 62 } 63 64 gmsDb := memory.NewDatabase("gms_db") 65 gmsTable := memory.NewLocalTable(gmsDb, name, sqlSch, nil) 66 gmsTable.EnablePrimaryKeyIndexes() 67 return &fulltextTable{ 68 GMSTable: gmsTable, 69 Table: tbl, 70 Sch: sch, 71 SqlSch: sqlSch.Schema, 72 }, nil 73 } 74 75 // Name implements the interface fulltext.EditableTable. 76 func (table *fulltextTable) Name() string { 77 return table.GMSTable.Name() 78 } 79 80 // String implements the interface fulltext.EditableTable. 81 func (table *fulltextTable) String() string { 82 return table.GMSTable.String() 83 } 84 85 // Schema implements the interface fulltext.EditableTable. 86 func (table *fulltextTable) Schema() sql.Schema { 87 return table.GMSTable.Schema() 88 } 89 90 // Collation implements the interface fulltext.EditableTable. 91 func (table *fulltextTable) Collation() sql.CollationID { 92 return table.GMSTable.Collation() 93 } 94 95 // Partitions implements the interface fulltext.EditableTable. 96 func (table *fulltextTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) { 97 return table.GMSTable.Partitions(ctx) 98 } 99 100 // PartitionRows implements the interface fulltext.EditableTable. 101 func (table *fulltextTable) PartitionRows(ctx *sql.Context, partition sql.Partition) (sql.RowIter, error) { 102 return table.GMSTable.PartitionRows(ctx, partition) 103 } 104 105 // Inserter implements the interface fulltext.EditableTable. 106 func (table *fulltextTable) Inserter(ctx *sql.Context) sql.RowInserter { 107 return table.GMSTable.Inserter(ctx) 108 } 109 110 // Updater implements the interface fulltext.EditableTable. 111 func (table *fulltextTable) Updater(ctx *sql.Context) sql.RowUpdater { 112 return table.GMSTable.Updater(ctx) 113 } 114 115 // Deleter implements the interface fulltext.EditableTable. 116 func (table *fulltextTable) Deleter(ctx *sql.Context) sql.RowDeleter { 117 return table.GMSTable.Deleter(ctx) 118 } 119 120 // IndexedAccess implements the interface fulltext.EditableTable. 121 func (table *fulltextTable) IndexedAccess(lookup sql.IndexLookup) sql.IndexedTable { 122 return table.GMSTable.IndexedAccess(lookup) 123 } 124 125 // GetIndexes implements the interface fulltext.EditableTable. 126 func (table *fulltextTable) GetIndexes(ctx *sql.Context) ([]sql.Index, error) { 127 return table.GMSTable.GetIndexes(ctx) 128 } 129 130 // PreciseMatch implements the interface fulltext.EditableTable. 131 func (table *fulltextTable) PreciseMatch() bool { 132 return false 133 } 134 135 // ApplyToTable writes the data from the internal GMS table to the internal Dolt table, then returns the updated Dolt 136 // table. The updated Dolt table is not stored. 137 func (table *fulltextTable) ApplyToTable(ctx *sql.Context) (*doltdb.Table, error) { 138 partIter, err := table.GMSTable.Partitions(ctx) 139 if err != nil { 140 return nil, err 141 } 142 rowIter := sql.NewTableRowIter(ctx, table.GMSTable, partIter) 143 144 idx, err := table.Table.GetRowData(ctx) 145 if err != nil { 146 return nil, err 147 } 148 m := durable.ProllyMapFromIndex(idx) 149 keyDesc, valDesc := m.Descriptors() 150 keyMap, valMap := ordinalMappingsFromSchema(table.SqlSch, table.Sch) 151 mut := m.Mutate() 152 keyBld := val.NewTupleBuilder(keyDesc) 153 valBld := val.NewTupleBuilder(valDesc) 154 155 sqlRow, err := rowIter.Next(ctx) 156 for ; err == nil; sqlRow, err = rowIter.Next(ctx) { 157 for to := range keyMap { 158 from := keyMap.MapOrdinal(to) 159 if err = tree.PutField(ctx, mut.NodeStore(), keyBld, to, sqlRow[from]); err != nil { 160 return nil, err 161 } 162 } 163 k := keyBld.Build(sharePool) 164 165 for to := range valMap { 166 from := valMap.MapOrdinal(to) 167 if err = tree.PutField(ctx, mut.NodeStore(), valBld, to, sqlRow[from]); err != nil { 168 return nil, err 169 } 170 } 171 v := valBld.Build(sharePool) 172 173 if err = mut.Put(ctx, k, v); err != nil { 174 return nil, err 175 } 176 } 177 if err != nil && err != io.EOF { 178 return nil, err 179 } 180 181 mapped, err := mut.Map(ctx) 182 if err != nil { 183 return nil, err 184 } 185 return table.Table.UpdateRows(ctx, durable.IndexFromProllyMap(mapped)) 186 } 187 188 func ordinalMappingsFromSchema(from sql.Schema, to schema.Schema) (km, vm val.OrdinalMapping) { 189 km = makeOrdinalMapping(from, to.GetPKCols()) 190 vm = makeOrdinalMapping(from, to.GetNonPKCols()) 191 return 192 } 193 194 func makeOrdinalMapping(from sql.Schema, to *schema.ColCollection) (m val.OrdinalMapping) { 195 m = make(val.OrdinalMapping, len(to.GetColumns())) 196 for i := range m { 197 name := to.GetByIndex(i).Name 198 for j, col := range from { 199 if col.Name == name { 200 m[i] = j 201 } 202 } 203 } 204 return 205 }