github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/save_table.go (about)

     1  // Copyright 2019 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 sql
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    18  	"github.com/cockroachdb/errors"
    19  )
    20  
    21  // saveTableNode is used for internal testing. It is a node that passes through
    22  // input data but saves it in a table. The table can be used subsequently, e.g.
    23  // to look at statistics.
    24  //
    25  // The node creates the table on startup. If the table exists, it errors out.
    26  type saveTableNode struct {
    27  	source planNode
    28  
    29  	target tree.TableName
    30  
    31  	// Column names from the saved table. These could be different than the names
    32  	// of the columns in the source plan. Note that saveTableNode passes through
    33  	// the source plan's column names.
    34  	colNames []string
    35  
    36  	run struct {
    37  		// vals accumulates a ValuesClause with the rows.
    38  		vals tree.ValuesClause
    39  	}
    40  }
    41  
    42  // saveTableInsertBatch is the number of rows per issued INSERT statement.
    43  const saveTableInsertBatch = 100
    44  
    45  func (p *planner) makeSaveTable(
    46  	source planNode, target *tree.TableName, colNames []string,
    47  ) planNode {
    48  	return &saveTableNode{source: source, target: *target, colNames: colNames}
    49  }
    50  
    51  func (n *saveTableNode) startExec(params runParams) error {
    52  	create := &tree.CreateTable{
    53  		Table: n.target,
    54  	}
    55  
    56  	cols := planColumns(n.source)
    57  	if len(n.colNames) != len(cols) {
    58  		return errors.AssertionFailedf(
    59  			"number of column names (%d) does not match number of columns (%d)",
    60  			len(n.colNames), len(cols),
    61  		)
    62  	}
    63  	for i := 0; i < len(cols); i++ {
    64  		def := &tree.ColumnTableDef{
    65  			Name: tree.Name(n.colNames[i]),
    66  			Type: cols[i].Typ,
    67  		}
    68  		def.Nullable.Nullability = tree.SilentNull
    69  		create.Defs = append(create.Defs, def)
    70  	}
    71  
    72  	_, err := params.p.ExtendedEvalContext().ExecCfg.InternalExecutor.Exec(
    73  		params.ctx,
    74  		"create save table",
    75  		nil, /* txn */
    76  		create.String(),
    77  	)
    78  	return err
    79  }
    80  
    81  // issue inserts rows into the target table of the saveTableNode.
    82  func (n *saveTableNode) issue(params runParams) error {
    83  	if v := &n.run.vals; len(v.Rows) > 0 {
    84  		stmt := fmt.Sprintf("INSERT INTO %s %s", n.target.String(), v.String())
    85  		if _, err := params.p.ExtendedEvalContext().ExecCfg.InternalExecutor.Exec(
    86  			params.ctx,
    87  			"insert into save table",
    88  			nil, /* txn */
    89  			stmt,
    90  		); err != nil {
    91  			return errors.Wrapf(err, "while running %s", stmt)
    92  		}
    93  		v.Rows = nil
    94  	}
    95  	return nil
    96  }
    97  
    98  // Next is part of the planNode interface.
    99  func (n *saveTableNode) Next(params runParams) (bool, error) {
   100  	res, err := n.source.Next(params)
   101  	if err != nil {
   102  		return res, err
   103  	}
   104  	if !res {
   105  		// We are done. Insert any accumulated rows.
   106  		err := n.issue(params)
   107  		return false, err
   108  	}
   109  	row := n.source.Values()
   110  	exprs := make(tree.Exprs, len(row))
   111  	for i := range row {
   112  		exprs[i] = row[i]
   113  	}
   114  	n.run.vals.Rows = append(n.run.vals.Rows, exprs)
   115  	if len(n.run.vals.Rows) >= saveTableInsertBatch {
   116  		if err := n.issue(params); err != nil {
   117  			return false, err
   118  		}
   119  	}
   120  	return true, nil
   121  }
   122  
   123  // Values is part of the planNode interface.
   124  func (n *saveTableNode) Values() tree.Datums {
   125  	return n.source.Values()
   126  }
   127  
   128  // Close is part of the planNode interface.
   129  func (n *saveTableNode) Close(ctx context.Context) {
   130  	n.source.Close(ctx)
   131  }