github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/row/noms_row.go (about) 1 // Copyright 2019 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 row 16 17 import ( 18 "errors" 19 "fmt" 20 21 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 22 "github.com/dolthub/dolt/go/store/types" 23 ) 24 25 type nomsRow struct { 26 key TaggedValues 27 value TaggedValues 28 nbf *types.NomsBinFormat 29 } 30 31 var _ Row = nomsRow{} 32 33 func pkRowFromNoms(sch schema.Schema, nomsKey, nomsVal types.Tuple) (Row, error) { 34 keySl, err := nomsKey.AsSlice() 35 if err != nil { 36 return nil, err 37 } 38 39 valSl, err := nomsVal.AsSlice() 40 if err != nil { 41 return nil, err 42 } 43 44 allCols := sch.GetAllCols() 45 46 err = IterPkTuple(keySl, func(tag uint64, val types.Value) (stop bool, err error) { 47 // The IsKeyless check in FromNoms misses keyless index schemas, even though 48 // the output tuple is a keyless index that contains a KeylessRowIdTag. 49 // NomsRangeReader breaks without this. 50 // A longer term fix could separate record vs index parsing, each of 51 // which is different for keyless vs keyed tables. 52 if tag == schema.KeylessRowIdTag { 53 return false, nil 54 } 55 col, ok := allCols.GetByTag(tag) 56 57 if !ok { 58 return false, errors.New("Trying to set a value on an unknown tag is a bug for the key. Validation should happen upstream. col:" + col.Name) 59 } else if !col.IsPartOfPK { 60 return false, errors.New("writing columns that are not part of the primary key to pk values. col:" + col.Name) 61 } else if !types.IsNull(val) && col.Kind != val.Kind() { 62 return false, errors.New("bug. Setting a value to an incorrect kind. col: " + col.Name) 63 } 64 65 return false, nil 66 }) 67 if err != nil { 68 return nil, err 69 } 70 71 filteredVals := make(TaggedValues, len(valSl)) 72 err = IterPkTuple(valSl, func(tag uint64, val types.Value) (stop bool, err error) { 73 col, ok := allCols.GetByTag(tag) 74 if !ok { 75 return false, nil 76 } 77 78 if col.IsPartOfPK { 79 return false, errors.New("writing columns that are part of the primary key to non-pk values. col:" + col.Name) 80 } else if !types.IsNull(val) { 81 // Column is GeometryKind and received PointKind, LineStringKind, or PolygonKind 82 if col.Kind == types.GeometryKind && types.IsGeometryKind(val.Kind()) { 83 filteredVals[tag] = val 84 } else if col.Kind == val.Kind() { 85 filteredVals[tag] = val 86 } else { 87 return false, errors.New("bug. Setting a value to an incorrect kind. col:" + col.Name) 88 } 89 90 } 91 92 return false, nil 93 }) 94 if err != nil { 95 return nil, err 96 } 97 98 taggedKeyVals, err := TaggedValuesFromTupleValueSlice(keySl) 99 if err != nil { 100 return nil, err 101 } 102 103 return nomsRow{taggedKeyVals, filteredVals, nomsKey.Format()}, nil 104 } 105 106 func (nr nomsRow) IterSchema(sch schema.Schema, cb func(tag uint64, val types.Value) (stop bool, err error)) (bool, error) { 107 err := sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (bool, error) { 108 value, _ := nr.GetColVal(tag) 109 return cb(tag, value) 110 }) 111 112 return false, err 113 } 114 115 func (nr nomsRow) IterCols(cb func(tag uint64, val types.Value) (bool, error)) (bool, error) { 116 stopped, err := nr.key.Iter(cb) 117 118 if err != nil { 119 return false, err 120 } 121 122 if !stopped { 123 stopped, err = nr.value.Iter(cb) 124 } 125 126 if err != nil { 127 return false, err 128 } 129 130 return stopped, nil 131 } 132 133 func (nr nomsRow) GetColVal(tag uint64) (types.Value, bool) { 134 val, ok := nr.key.Get(tag) 135 136 if !ok { 137 val, ok = nr.value.Get(tag) 138 } 139 140 return val, ok 141 } 142 143 func (nr nomsRow) SetColVal(tag uint64, val types.Value, sch schema.Schema) (Row, error) { 144 rowKey := nr.key 145 rowVal := nr.value 146 147 cols := sch.GetAllCols() 148 col, ok := cols.GetByTag(tag) 149 150 if ok { 151 if col.IsPartOfPK { 152 rowKey = nr.key.Set(tag, val) 153 } else { 154 rowVal = nr.value.Set(tag, val) 155 } 156 157 return nomsRow{rowKey, rowVal, nr.nbf}, nil 158 } 159 160 panic("can't set a column whose tag isn't in the schema. verify before calling this function.") 161 } 162 163 func (nr nomsRow) Format() *types.NomsBinFormat { 164 return nr.nbf 165 } 166 167 // TaggedValues implements the Row interface. 168 func (nr nomsRow) TaggedValues() (TaggedValues, error) { 169 tv := make(TaggedValues) 170 for k, v := range nr.key { 171 tv[k] = v 172 } 173 for k, v := range nr.value { 174 tv[k] = v 175 } 176 return tv, nil 177 } 178 179 func pkRowFromTaggedValues(nbf *types.NomsBinFormat, sch schema.Schema, colVals TaggedValues) (Row, error) { 180 allCols := sch.GetAllCols() 181 182 keyVals := make(TaggedValues) 183 nonKeyVals := make(TaggedValues) 184 185 _, err := colVals.Iter(func(tag uint64, val types.Value) (stop bool, err error) { 186 col, ok := allCols.GetByTag(tag) 187 188 if !ok { 189 return false, errors.New("Trying to set a value on an unknown tag is a bug. Validation should happen upstream.") 190 } else if col.IsPartOfPK { 191 keyVals[tag] = val 192 } else { 193 nonKeyVals[tag] = val 194 } 195 return false, nil 196 }) 197 198 if err != nil { 199 return nil, err 200 } 201 202 return fromTaggedVals(nbf, sch, keyVals, nonKeyVals) 203 } 204 205 // fromTaggedVals will take a schema, a map of tag to value for the key, and a map of tag to value for non key values, 206 // and generates a row. When a schema adds or removes columns from the non-key portion of the row, the schema will be 207 // updated, but the rows will not be touched. So the non-key portion of the row may contain values that are not in the 208 // schema (The keys must match the schema though). 209 func fromTaggedVals(nbf *types.NomsBinFormat, sch schema.Schema, keyVals, nonKeyVals TaggedValues) (Row, error) { 210 allCols := sch.GetAllCols() 211 212 _, err := keyVals.Iter(func(tag uint64, val types.Value) (stop bool, err error) { 213 col, ok := allCols.GetByTag(tag) 214 215 if !ok { 216 return false, errors.New("Trying to set a value on an unknown tag is a bug for the key. Validation should happen upstream. col:" + col.Name) 217 } else if !col.IsPartOfPK { 218 return false, errors.New("writing columns that are not part of the primary key to pk values. col:" + col.Name) 219 } else if !types.IsNull(val) && col.Kind != val.Kind() { 220 if col.Kind == types.GeometryKind && types.IsGeometryKind(val.Kind()) { 221 return false, nil 222 } 223 return false, errors.New("bug. Setting a value to an incorrect kind. col: " + col.Name) 224 } 225 226 return false, nil 227 }) 228 229 if err != nil { 230 return nil, err 231 } 232 233 filteredVals := make(TaggedValues, len(nonKeyVals)) 234 _, err = nonKeyVals.Iter(func(tag uint64, val types.Value) (stop bool, err error) { 235 col, ok := allCols.GetByTag(tag) 236 if !ok { 237 return false, nil 238 } 239 240 if col.IsPartOfPK { 241 return false, errors.New("writing columns that are part of the primary key to non-pk values. col:" + col.Name) 242 } else if !types.IsNull(val) && col.Kind != val.Kind() { 243 if col.Kind == types.GeometryKind && types.IsGeometryKind(val.Kind()) { 244 filteredVals[tag] = val 245 return false, nil 246 } 247 return false, errors.New("bug. Setting a value to an incorrect kind. col:" + col.Name) 248 } else { 249 filteredVals[tag] = val 250 } 251 252 return false, nil 253 }) 254 255 if err != nil { 256 return nil, err 257 } 258 259 return nomsRow{keyVals, filteredVals, nbf}, nil 260 } 261 262 func (nr nomsRow) NomsMapKey(sch schema.Schema) types.LesserValuable { 263 return nr.key.NomsTupleForPKCols(nr.nbf, sch.GetPKCols()) 264 } 265 266 func (nr nomsRow) NomsMapValue(sch schema.Schema) types.Valuable { 267 return nr.value.NomsTupleForNonPKCols(nr.nbf, sch.GetNonPKCols()) 268 } 269 270 func (nr nomsRow) NomsMapKeyTuple(sch schema.Schema, tf *types.TupleFactory) (types.Tuple, error) { 271 tv := nr.key.NomsTupleForPKCols(nr.nbf, sch.GetPKCols()) 272 273 if tf != nil { 274 return tf.Create(tv.vs...) 275 } else { 276 return types.NewTuple(tv.nbf, tv.vs...) 277 } 278 } 279 280 func (nr nomsRow) NomsMapValueTuple(sch schema.Schema, tf *types.TupleFactory) (types.Tuple, error) { 281 tv := nr.value.NomsTupleForNonPKCols(nr.nbf, sch.GetNonPKCols()) 282 283 if tf != nil { 284 return tf.Create(tv.vs...) 285 } else { 286 return types.NewTuple(tv.nbf, tv.vs...) 287 } 288 } 289 290 // ReduceToIndexKeys creates a full key, partial key, and value tuple from the given row (first tuple being the full key). Please 291 // refer to the note in the index editor for more information regarding partial keys. NomsRows map always 292 // keys to an empty value tuple. 293 func (nr nomsRow) ReduceToIndexKeys(idx schema.Index, tf *types.TupleFactory) (types.Tuple, types.Tuple, types.Tuple, error) { 294 vals := make([]types.Value, 0, len(idx.AllTags())*2) 295 for _, tag := range idx.AllTags() { 296 val, ok := nr.GetColVal(tag) 297 if !ok { 298 val = types.NullValue 299 } 300 vals = append(vals, types.Uint(tag), val) 301 } 302 303 var err error 304 var fullKey types.Tuple 305 var partialKey types.Tuple 306 if tf == nil { 307 fullKey, err = types.NewTuple(nr.Format(), vals...) 308 if err != nil { 309 return types.Tuple{}, types.Tuple{}, types.Tuple{}, err 310 } 311 partialKey, err = types.NewTuple(nr.Format(), vals[:idx.Count()*2]...) 312 if err != nil { 313 return types.Tuple{}, types.Tuple{}, types.Tuple{}, err 314 } 315 } else { 316 fullKey, err = tf.Create(vals...) 317 if err != nil { 318 return types.Tuple{}, types.Tuple{}, types.Tuple{}, err 319 } 320 partialKey, err = tf.Create(vals[:idx.Count()*2]...) 321 if err != nil { 322 return types.Tuple{}, types.Tuple{}, types.Tuple{}, err 323 } 324 } 325 326 return fullKey, partialKey, types.EmptyTuple(nr.Format()), nil 327 } 328 329 func IterPkTuple(tvs types.TupleValueSlice, cb func(tag uint64, val types.Value) (stop bool, err error)) error { 330 if len(tvs)%2 != 0 { 331 return fmt.Errorf("expected len(TupleValueSlice) to be even, got %d", len(tvs)) 332 } 333 334 l := len(tvs) 335 for i := 0; i < l; i += 2 { 336 stop, err := cb(uint64(tvs[i].(types.Uint)), tvs[i+1]) 337 338 if err != nil { 339 return err 340 } 341 342 if stop { 343 break 344 } 345 } 346 347 return nil 348 }