github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/values.go (about) 1 // Copyright 2015 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 "strconv" 16 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/rowcontainer" 20 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 21 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 22 "github.com/cockroachdb/cockroach/pkg/sql/types" 23 "github.com/cockroachdb/errors" 24 ) 25 26 type valuesNode struct { 27 columns sqlbase.ResultColumns 28 tuples [][]tree.TypedExpr 29 30 // specifiedInQuery is set if the valuesNode represents a literal 31 // relational expression that was present in the original SQL text, 32 // as opposed to e.g. a valuesNode resulting from the expansion of 33 // a vtable value generator. This changes distsql physical planning. 34 specifiedInQuery bool 35 36 valuesRun 37 } 38 39 // Values implements the VALUES clause. 40 func (p *planner) Values( 41 ctx context.Context, origN tree.Statement, desiredTypes []*types.T, 42 ) (planNode, error) { 43 v := &valuesNode{ 44 specifiedInQuery: true, 45 } 46 47 // If we have names, extract them. 48 var n *tree.ValuesClause 49 switch t := origN.(type) { 50 case *tree.ValuesClauseWithNames: 51 n = &t.ValuesClause 52 case *tree.ValuesClause: 53 n = t 54 default: 55 return nil, errors.AssertionFailedf("unhandled case in values: %T %v", origN, origN) 56 } 57 58 if len(n.Rows) == 0 { 59 return v, nil 60 } 61 62 numCols := len(n.Rows[0]) 63 64 v.tuples = make([][]tree.TypedExpr, 0, len(n.Rows)) 65 tupleBuf := make([]tree.TypedExpr, len(n.Rows)*numCols) 66 67 v.columns = make(sqlbase.ResultColumns, 0, numCols) 68 69 // We need to save and restore the previous value of the field in 70 // semaCtx in case we are recursively called within a subquery 71 // context. 72 defer p.semaCtx.Properties.Restore(p.semaCtx.Properties) 73 74 // Ensure there are no special functions in the clause. 75 p.semaCtx.Properties.Require("VALUES", tree.RejectSpecial) 76 77 for num, tuple := range n.Rows { 78 if a, e := len(tuple), numCols; a != e { 79 return nil, newValuesListLenErr(e, a) 80 } 81 82 // Chop off prefix of tupleBuf and limit its capacity. 83 tupleRow := tupleBuf[:numCols:numCols] 84 tupleBuf = tupleBuf[numCols:] 85 86 for i, expr := range tuple { 87 desired := types.Any 88 if len(desiredTypes) > i { 89 desired = desiredTypes[i] 90 } 91 92 // Clear the properties so we can check them below. 93 typedExpr, err := p.analyzeExpr(ctx, expr, nil, tree.IndexedVarHelper{}, desired, false, "") 94 if err != nil { 95 return nil, err 96 } 97 98 typ := typedExpr.ResolvedType() 99 if num == 0 { 100 v.columns = append(v.columns, sqlbase.ResultColumn{Name: "column" + strconv.Itoa(i+1), Typ: typ}) 101 } else if v.columns[i].Typ.Family() == types.UnknownFamily { 102 v.columns[i].Typ = typ 103 } else if typ.Family() != types.UnknownFamily && !typ.Equivalent(v.columns[i].Typ) { 104 return nil, pgerror.Newf(pgcode.DatatypeMismatch, 105 "VALUES types %s and %s cannot be matched", typ, v.columns[i].Typ) 106 } 107 108 tupleRow[i] = typedExpr 109 } 110 v.tuples = append(v.tuples, tupleRow) 111 } 112 return v, nil 113 } 114 115 func (p *planner) newContainerValuesNode(columns sqlbase.ResultColumns, capacity int) *valuesNode { 116 return &valuesNode{ 117 columns: columns, 118 valuesRun: valuesRun{ 119 rows: rowcontainer.NewRowContainer( 120 p.EvalContext().Mon.MakeBoundAccount(), sqlbase.ColTypeInfoFromResCols(columns), capacity, 121 ), 122 }, 123 } 124 } 125 126 // valuesRun is the run-time state of a valuesNode during local execution. 127 type valuesRun struct { 128 rows *rowcontainer.RowContainer 129 nextRow int // The index of the next row. 130 } 131 132 func (n *valuesNode) startExec(params runParams) error { 133 if n.rows != nil { 134 // n.rows was already created in newContainerValuesNode. 135 // Nothing to do here. 136 return nil 137 } 138 139 // This node is coming from a SQL query (as opposed to sortNode and 140 // others that create a valuesNode internally for storing results 141 // from other planNodes), so its expressions need evaluating. 142 // This may run subqueries. 143 n.rows = rowcontainer.NewRowContainer( 144 params.extendedEvalCtx.Mon.MakeBoundAccount(), 145 sqlbase.ColTypeInfoFromResCols(n.columns), 146 len(n.tuples), 147 ) 148 149 row := make([]tree.Datum, len(n.columns)) 150 for _, tupleRow := range n.tuples { 151 for i, typedExpr := range tupleRow { 152 var err error 153 row[i], err = typedExpr.Eval(params.EvalContext()) 154 if err != nil { 155 return err 156 } 157 } 158 if _, err := n.rows.AddRow(params.ctx, row); err != nil { 159 return err 160 } 161 } 162 163 return nil 164 } 165 166 func (n *valuesNode) Next(runParams) (bool, error) { 167 if n.nextRow >= n.rows.Len() { 168 return false, nil 169 } 170 n.nextRow++ 171 return true, nil 172 } 173 174 func (n *valuesNode) Values() tree.Datums { 175 return n.rows.At(n.nextRow - 1) 176 } 177 178 func (n *valuesNode) Close(ctx context.Context) { 179 if n.rows != nil { 180 n.rows.Close(ctx) 181 n.rows = nil 182 } 183 } 184 185 func newValuesListLenErr(exp, got int) error { 186 return pgerror.Newf( 187 pgcode.Syntax, 188 "VALUES lists must all be the same length, expected %d columns, found %d", 189 exp, got) 190 }