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 }