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  }