github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/row/row_converter.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package row 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/roachpb" 17 "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins" 18 "github.com/cockroachdb/cockroach/pkg/sql/sem/transform" 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 20 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 21 "github.com/cockroachdb/cockroach/pkg/sql/types" 22 "github.com/cockroachdb/cockroach/pkg/util" 23 "github.com/cockroachdb/errors" 24 ) 25 26 // KVInserter implements the putter interface. 27 type KVInserter func(roachpb.KeyValue) 28 29 // CPut is not implmented. 30 func (i KVInserter) CPut(key, value interface{}, expValue *roachpb.Value) { 31 panic("unimplemented") 32 } 33 34 // Del is not implemented. 35 func (i KVInserter) Del(key ...interface{}) { 36 // This is called when there are multiple column families to ensure that 37 // existing data is cleared. With the exception of IMPORT INTO, the entire 38 // existing keyspace in any IMPORT is guaranteed to be empty, so we don't have 39 // to worry about it. 40 // 41 // IMPORT INTO disallows overwriting an existing row, so we're also okay here. 42 // The reason this works is that row existence is precisely defined as whether 43 // column family 0 exists, meaning that we write column family 0 even if all 44 // the non-pk columns in it are NULL. It follows that either the row does 45 // exist and the imported column family 0 will conflict (and the IMPORT INTO 46 // will fail) or the row does not exist (and thus the column families are all 47 // empty). 48 } 49 50 // Put method of the putter interface. 51 func (i KVInserter) Put(key, value interface{}) { 52 i(roachpb.KeyValue{ 53 Key: *key.(*roachpb.Key), 54 Value: *value.(*roachpb.Value), 55 }) 56 } 57 58 // InitPut method of the putter interface. 59 func (i KVInserter) InitPut(key, value interface{}, failOnTombstones bool) { 60 i(roachpb.KeyValue{ 61 Key: *key.(*roachpb.Key), 62 Value: *value.(*roachpb.Value), 63 }) 64 } 65 66 // GenerateInsertRow prepares a row tuple for insertion. It fills in default 67 // expressions, verifies non-nullable columns, and checks column widths. 68 // 69 // The result is a row tuple providing values for every column in insertCols. 70 // This results contains: 71 // 72 // - the values provided by rowVals, the tuple of source values. The 73 // caller ensures this provides values 1-to-1 to the prefix of 74 // insertCols that was specified explicitly in the INSERT statement. 75 // - the default values for any additional columns in insertCols that 76 // have default values in defaultExprs. 77 // - the computed values for any additional columns in insertCols 78 // that are computed. The mapping in rowContainerForComputedCols 79 // maps the indexes of the comptuedCols/computeExpr slices 80 // back into indexes in the result row tuple. 81 // 82 func GenerateInsertRow( 83 defaultExprs []tree.TypedExpr, 84 computeExprs []tree.TypedExpr, 85 insertCols []sqlbase.ColumnDescriptor, 86 computedCols []sqlbase.ColumnDescriptor, 87 evalCtx *tree.EvalContext, 88 tableDesc *sqlbase.ImmutableTableDescriptor, 89 rowVals tree.Datums, 90 rowContainerForComputedVals *sqlbase.RowIndexedVarContainer, 91 ) (tree.Datums, error) { 92 // The values for the row may be shorter than the number of columns being 93 // inserted into. Generate default values for those columns using the 94 // default expressions. This will not happen if the row tuple was produced 95 // by a ValuesClause, because all default expressions will have been populated 96 // already by fillDefaults. 97 if len(rowVals) < len(insertCols) { 98 // It's not cool to append to the slice returned by a node; make a copy. 99 oldVals := rowVals 100 rowVals = make(tree.Datums, len(insertCols)) 101 copy(rowVals, oldVals) 102 103 for i := len(oldVals); i < len(insertCols); i++ { 104 if defaultExprs == nil { 105 rowVals[i] = tree.DNull 106 continue 107 } 108 d, err := defaultExprs[i].Eval(evalCtx) 109 if err != nil { 110 return nil, err 111 } 112 rowVals[i] = d 113 } 114 } 115 116 // Generate the computed values, if needed. 117 if len(computeExprs) > 0 { 118 rowContainerForComputedVals.CurSourceRow = rowVals 119 evalCtx.PushIVarContainer(rowContainerForComputedVals) 120 for i := range computedCols { 121 // Note that even though the row is not fully constructed at this point, 122 // since we disallow computed columns from referencing other computed 123 // columns, all the columns which could possibly be referenced *are* 124 // available. 125 d, err := computeExprs[i].Eval(evalCtx) 126 if err != nil { 127 return nil, errors.Wrapf(err, "computed column %s", tree.ErrString((*tree.Name)(&computedCols[i].Name))) 128 } 129 rowVals[rowContainerForComputedVals.Mapping[computedCols[i].ID]] = d 130 } 131 evalCtx.PopIVarContainer() 132 } 133 134 // Verify the column constraints. 135 // 136 // We would really like to use enforceLocalColumnConstraints() here, 137 // but this is not possible because of some brain damage in the 138 // Insert() constructor, which causes insertCols to contain 139 // duplicate columns descriptors: computed columns are listed twice, 140 // one will receive a NULL value and one will receive a comptued 141 // value during execution. It "works out in the end" because the 142 // latter (non-NULL) value overwrites the earlier, but 143 // enforceLocalColumnConstraints() does not know how to reason about 144 // this. 145 // 146 // In the end it does not matter much, this code is going away in 147 // favor of the (simpler, correct) code in the CBO. 148 149 // Check to see if NULL is being inserted into any non-nullable column. 150 for _, col := range tableDesc.WritableColumns() { 151 if !col.Nullable { 152 if i, ok := rowContainerForComputedVals.Mapping[col.ID]; !ok || rowVals[i] == tree.DNull { 153 return nil, sqlbase.NewNonNullViolationError(col.Name) 154 } 155 } 156 } 157 158 // Ensure that the values honor the specified column widths. 159 for i := 0; i < len(insertCols); i++ { 160 outVal, err := sqlbase.AdjustValueToColumnType(insertCols[i].Type, rowVals[i], &insertCols[i].Name) 161 if err != nil { 162 return nil, err 163 } 164 rowVals[i] = outVal 165 } 166 167 return rowVals, nil 168 } 169 170 // KVBatch represents a batch of KVs generated from converted rows. 171 type KVBatch struct { 172 // Source is where the row data in the batch came from. 173 Source int32 174 // LastRow is the index of the last converted row in source in this batch. 175 LastRow int64 176 // Progress represents the fraction of the input that generated this row. 177 Progress float32 178 // KVs is the actual converted KV data. 179 KVs []roachpb.KeyValue 180 } 181 182 // DatumRowConverter converts Datums into kvs and streams it to the destination 183 // channel. 184 type DatumRowConverter struct { 185 // current row buf 186 Datums []tree.Datum 187 188 // kv destination and current batch 189 KvCh chan<- KVBatch 190 KvBatch KVBatch 191 BatchCap int 192 193 tableDesc *sqlbase.ImmutableTableDescriptor 194 195 // Tracks which column indices in the set of visible columns are part of the 196 // user specified target columns. This can be used before populating Datums 197 // to filter out unwanted column data. 198 IsTargetCol map[int]struct{} 199 200 // The rest of these are derived from tableDesc, just cached here. 201 hidden int 202 ri Inserter 203 EvalCtx *tree.EvalContext 204 cols []sqlbase.ColumnDescriptor 205 VisibleCols []sqlbase.ColumnDescriptor 206 VisibleColTypes []*types.T 207 defaultExprs []tree.TypedExpr 208 computedIVarContainer sqlbase.RowIndexedVarContainer 209 210 // FractionFn is used to set the progress header in KVBatches. 211 CompletedRowFn func() int64 212 FractionFn func() float32 213 } 214 215 var kvDatumRowConverterBatchSize = 5000 216 217 // TestingSetDatumRowConverterBatchSize sets kvDatumRowConverterBatchSize and returns function to 218 // reset this setting back to its old value. 219 func TestingSetDatumRowConverterBatchSize(newSize int) func() { 220 kvDatumRowConverterBatchSize = newSize 221 return func() { 222 kvDatumRowConverterBatchSize = 5000 223 } 224 } 225 226 // NewDatumRowConverter returns an instance of a DatumRowConverter. 227 func NewDatumRowConverter( 228 ctx context.Context, 229 tableDesc *sqlbase.TableDescriptor, 230 targetColNames tree.NameList, 231 evalCtx *tree.EvalContext, 232 kvCh chan<- KVBatch, 233 ) (*DatumRowConverter, error) { 234 immutDesc := sqlbase.NewImmutableTableDescriptor(*tableDesc) 235 c := &DatumRowConverter{ 236 tableDesc: immutDesc, 237 KvCh: kvCh, 238 EvalCtx: evalCtx, 239 } 240 241 var targetColDescriptors []sqlbase.ColumnDescriptor 242 var err error 243 // IMPORT INTO allows specifying target columns which could be a subset of 244 // immutDesc.VisibleColumns. If no target columns are specified we assume all 245 // columns of the table descriptor are to be inserted into. 246 if len(targetColNames) != 0 { 247 if targetColDescriptors, err = sqlbase.ProcessTargetColumns(immutDesc, targetColNames, 248 true /* ensureColumns */, false /* allowMutations */); err != nil { 249 return nil, err 250 } 251 } else { 252 targetColDescriptors = immutDesc.VisibleColumns() 253 } 254 255 isTargetColID := make(map[sqlbase.ColumnID]struct{}) 256 for _, col := range targetColDescriptors { 257 isTargetColID[col.ID] = struct{}{} 258 } 259 260 c.IsTargetCol = make(map[int]struct{}) 261 for i, col := range targetColDescriptors { 262 if _, ok := isTargetColID[col.ID]; !ok { 263 continue 264 } 265 c.IsTargetCol[i] = struct{}{} 266 } 267 268 var txCtx transform.ExprTransformContext 269 // We do not currently support DEFAULT expressions on target or non-target 270 // columns. All non-target columns must be nullable and will be set to NULL 271 // during import. We do however support DEFAULT on hidden columns (which is 272 // only the default _rowid one). This allows those expressions to run. 273 cols, defaultExprs, err := sqlbase.ProcessDefaultColumns(ctx, targetColDescriptors, immutDesc, &txCtx, c.EvalCtx) 274 if err != nil { 275 return nil, errors.Wrap(err, "process default columns") 276 } 277 278 ri, err := MakeInserter( 279 ctx, 280 nil, /* txn */ 281 evalCtx.Codec, 282 immutDesc, 283 cols, 284 SkipFKs, 285 nil, /* fkTables */ 286 &sqlbase.DatumAlloc{}, 287 ) 288 if err != nil { 289 return nil, errors.Wrap(err, "make row inserter") 290 } 291 292 c.ri = ri 293 c.cols = cols 294 c.defaultExprs = defaultExprs 295 296 c.VisibleCols = targetColDescriptors 297 c.VisibleColTypes = make([]*types.T, len(c.VisibleCols)) 298 for i := range c.VisibleCols { 299 c.VisibleColTypes[i] = c.VisibleCols[i].DatumType() 300 } 301 302 c.Datums = make([]tree.Datum, len(targetColDescriptors), len(cols)) 303 304 // Check for a hidden column. This should be the unique_rowid PK if present. 305 c.hidden = -1 306 for i := range cols { 307 col := &cols[i] 308 if col.Hidden { 309 if col.DefaultExpr == nil || *col.DefaultExpr != "unique_rowid()" || c.hidden != -1 { 310 return nil, errors.New("unexpected hidden column") 311 } 312 c.hidden = i 313 c.Datums = append(c.Datums, nil) 314 } 315 } 316 if len(c.Datums) != len(cols) { 317 return nil, errors.New("unexpected hidden column") 318 } 319 320 padding := 2 * (len(immutDesc.Indexes) + len(immutDesc.Families)) 321 c.BatchCap = kvDatumRowConverterBatchSize + padding 322 c.KvBatch.KVs = make([]roachpb.KeyValue, 0, c.BatchCap) 323 324 c.computedIVarContainer = sqlbase.RowIndexedVarContainer{ 325 Mapping: ri.InsertColIDtoRowIndex, 326 Cols: immutDesc.Columns, 327 } 328 return c, nil 329 } 330 331 const rowIDBits = 64 - builtins.NodeIDBits 332 333 // Row inserts kv operations into the current kv batch, and triggers a SendBatch 334 // if necessary. 335 func (c *DatumRowConverter) Row(ctx context.Context, sourceID int32, rowIndex int64) error { 336 if c.hidden >= 0 { 337 // We don't want to call unique_rowid() for the hidden PK column because it 338 // is not idempotent and has unfortunate overlapping of output spans since 339 // it puts the uniqueness-ensuring per-generator part (nodeID) in the 340 // low-bits. Instead, make our own IDs that attempt to keep each generator 341 // (sourceID) writing to its own key-space with sequential rowIndexes 342 // mapping to sequential unique IDs, by putting the rowID in the lower 343 // bits. To avoid collisions with the SQL-genenerated IDs (at least for a 344 // very long time) we also flip the top bit to 1. 345 // 346 // Producing sequential keys in non-overlapping spans for each source yields 347 // observed improvements in ingestion performance of ~2-3x and even more 348 // significant reductions in required compactions during IMPORT. 349 // 350 // TODO(dt): Note that currently some callers (e.g. CSV IMPORT, which can be 351 // used on a table more than once) offset their rowIndex by a wall-time at 352 // which their overall job is run, so that subsequent ingestion jobs pick 353 // different row IDs for the i'th row and don't collide. However such 354 // time-offset rowIDs mean each row imported consumes some unit of time that 355 // must then elapse before the next IMPORT could run without colliding e.g. 356 // a 100m row file would use 10µs/row or ~17min worth of IDs. For now it is 357 // likely that IMPORT's write-rate is still the limiting factor, but this 358 // scheme means rowIndexes are very large (1 yr in 10s of µs is about 2^42). 359 // Finding an alternative scheme for avoiding collisions (like sourceID * 360 // fileIndex*desc.Version) could improve on this. For now, if this 361 // best-effort collision avoidance scheme doesn't work in some cases we can 362 // just recommend an explicit PK as a workaround. 363 avoidCollisionsWithSQLsIDs := uint64(1 << 63) 364 rowID := (uint64(sourceID) << rowIDBits) ^ uint64(rowIndex) 365 c.Datums[c.hidden] = tree.NewDInt(tree.DInt(avoidCollisionsWithSQLsIDs | rowID)) 366 } 367 368 // TODO(justin): we currently disallow computed columns in import statements. 369 var computeExprs []tree.TypedExpr 370 var computedCols []sqlbase.ColumnDescriptor 371 372 insertRow, err := GenerateInsertRow( 373 c.defaultExprs, computeExprs, c.cols, computedCols, c.EvalCtx, c.tableDesc, c.Datums, &c.computedIVarContainer) 374 if err != nil { 375 return errors.Wrap(err, "generate insert row") 376 } 377 // TODO(mgartner): Add partial index IDs to ignoreIndexes that we should 378 // not delete entries from. 379 var ignoreIndexes util.FastIntSet 380 if err := c.ri.InsertRow( 381 ctx, 382 KVInserter(func(kv roachpb.KeyValue) { 383 kv.Value.InitChecksum(kv.Key) 384 c.KvBatch.KVs = append(c.KvBatch.KVs, kv) 385 }), 386 insertRow, 387 ignoreIndexes, 388 true, /* ignoreConflicts */ 389 SkipFKs, 390 false, /* traceKV */ 391 ); err != nil { 392 return errors.Wrap(err, "insert row") 393 } 394 // If our batch is full, flush it and start a new one. 395 if len(c.KvBatch.KVs) >= kvDatumRowConverterBatchSize { 396 if err := c.SendBatch(ctx); err != nil { 397 return err 398 } 399 } 400 return nil 401 } 402 403 // SendBatch streams kv operations from the current KvBatch to the destination 404 // channel, and resets the KvBatch to empty. 405 func (c *DatumRowConverter) SendBatch(ctx context.Context) error { 406 if len(c.KvBatch.KVs) == 0 { 407 return nil 408 } 409 if c.FractionFn != nil { 410 c.KvBatch.Progress = c.FractionFn() 411 } 412 if c.CompletedRowFn != nil { 413 c.KvBatch.LastRow = c.CompletedRowFn() 414 } 415 select { 416 case c.KvCh <- c.KvBatch: 417 case <-ctx.Done(): 418 return ctx.Err() 419 } 420 c.KvBatch.KVs = make([]roachpb.KeyValue, 0, c.BatchCap) 421 return nil 422 }