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

     1  // Copyright 2018 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 optbuilder
    12  
    13  import (
    14  	"fmt"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    21  )
    22  
    23  // buildValuesClause builds a set of memo groups that represent the given values
    24  // clause.
    25  //
    26  // See Builder.buildStmt for a description of the remaining input and
    27  // return values.
    28  func (b *Builder) buildValuesClause(
    29  	values *tree.ValuesClause, desiredTypes []*types.T, inScope *scope,
    30  ) (outScope *scope) {
    31  	numRows := len(values.Rows)
    32  	numCols := 0
    33  	if numRows > 0 {
    34  		numCols = len(values.Rows[0])
    35  	}
    36  
    37  	// We need to save and restore the previous value of the field in
    38  	// semaCtx in case we are recursively called within a subquery
    39  	// context.
    40  	defer b.semaCtx.Properties.Restore(b.semaCtx.Properties)
    41  
    42  	// Ensure there are no special functions in the clause.
    43  	b.semaCtx.Properties.Require(exprKindValues.String(), tree.RejectSpecial)
    44  	inScope.context = exprKindValues
    45  
    46  	// Typing a VALUES clause is not trivial; consider:
    47  	//   VALUES (NULL), (1)
    48  	// We want to type the entire column as INT. For this, we must find the first
    49  	// expression that resolves to a definite type. Moreover, we want the NULL to
    50  	// be typed correctly; so once we figure out the type, we must go back and
    51  	// add casts as necessary. We do this column by column and store the groups in
    52  	// a linearized matrix.
    53  
    54  	// Bulk allocate ScalarListExpr slices: we need a matrix of size numRows by
    55  	// numCols and one slice of length numRows for the tuples.
    56  	elems := make(memo.ScalarListExpr, numRows*numCols+numRows)
    57  	tuples, elems := elems[:numRows], elems[numRows:]
    58  
    59  	colTypes := make([]*types.T, numCols)
    60  	for colIdx := range colTypes {
    61  		desired := types.Any
    62  		if colIdx < len(desiredTypes) {
    63  			desired = desiredTypes[colIdx]
    64  		}
    65  		colTypes[colIdx] = types.Unknown
    66  
    67  		elemPos := colIdx
    68  		for _, tuple := range values.Rows {
    69  			if numCols != len(tuple) {
    70  				reportValuesLenError(numCols, len(tuple))
    71  			}
    72  
    73  			expr := inScope.walkExprTree(tuple[colIdx])
    74  			texpr, err := tree.TypeCheck(b.ctx, expr, b.semaCtx, desired)
    75  			if err != nil {
    76  				panic(err)
    77  			}
    78  			if typ := texpr.ResolvedType(); typ.Family() != types.UnknownFamily {
    79  				if colTypes[colIdx].Family() == types.UnknownFamily {
    80  					colTypes[colIdx] = typ
    81  				} else if !typ.Equivalent(colTypes[colIdx]) {
    82  					panic(pgerror.Newf(pgcode.DatatypeMismatch,
    83  						"VALUES types %s and %s cannot be matched", typ, colTypes[colIdx]))
    84  				}
    85  			}
    86  			elems[elemPos] = b.buildScalar(texpr, inScope, nil, nil, nil)
    87  			elemPos += numCols
    88  		}
    89  
    90  		// If we still don't have a type for the column, set it to the desired type.
    91  		if colTypes[colIdx].Family() == types.UnknownFamily && desired.Family() != types.AnyFamily {
    92  			colTypes[colIdx] = desired
    93  		}
    94  
    95  		// Add casts to NULL values if necessary.
    96  		if colTypes[colIdx].Family() != types.UnknownFamily {
    97  			elemPos := colIdx
    98  			for range values.Rows {
    99  				if elems[elemPos].DataType().Family() == types.UnknownFamily {
   100  					elems[elemPos] = b.factory.ConstructCast(elems[elemPos], colTypes[colIdx])
   101  				}
   102  				elemPos += numCols
   103  			}
   104  		}
   105  	}
   106  
   107  	// Build the tuples.
   108  	tupleTyp := types.MakeTuple(colTypes)
   109  	for rowIdx := range tuples {
   110  		tuples[rowIdx] = b.factory.ConstructTuple(elems[:numCols], tupleTyp)
   111  		elems = elems[numCols:]
   112  	}
   113  
   114  	outScope = inScope.push()
   115  	for colIdx := 0; colIdx < numCols; colIdx++ {
   116  		// The column names for VALUES are column1, column2, etc.
   117  		alias := fmt.Sprintf("column%d", colIdx+1)
   118  		b.synthesizeColumn(outScope, alias, colTypes[colIdx], nil, nil /* scalar */)
   119  	}
   120  
   121  	colList := colsToColList(outScope.cols)
   122  	outScope.expr = b.factory.ConstructValues(tuples, &memo.ValuesPrivate{
   123  		Cols: colList,
   124  		ID:   b.factory.Metadata().NextUniqueID(),
   125  	})
   126  	return outScope
   127  }
   128  
   129  func reportValuesLenError(expected, actual int) {
   130  	panic(pgerror.Newf(
   131  		pgcode.Syntax,
   132  		"VALUES lists must all be the same length, expected %d columns, found %d",
   133  		expected, actual))
   134  }