github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/delegate/show_range_for_row.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 delegate 12 13 import ( 14 "encoding/hex" 15 "fmt" 16 17 "github.com/cockroachdb/cockroach/pkg/sql/opt/cat" 18 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 19 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 20 "github.com/cockroachdb/cockroach/pkg/sql/privilege" 21 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 22 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 23 "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" 24 "github.com/cockroachdb/errors" 25 ) 26 27 func (d *delegator) delegateShowRangeForRow(n *tree.ShowRangeForRow) (tree.Statement, error) { 28 flags := cat.Flags{AvoidDescriptorCaches: true} 29 idx, resName, err := cat.ResolveTableIndex(d.ctx, d.catalog, flags, &n.TableOrIndex) 30 if err != nil { 31 return nil, err 32 } 33 if err := d.catalog.CheckPrivilege(d.ctx, idx.Table(), privilege.SELECT); err != nil { 34 return nil, err 35 } 36 if idx.Table().IsVirtualTable() { 37 return nil, errors.New("SHOW RANGE FOR ROW may not be called on a virtual table") 38 } 39 span := idx.Span() 40 table := idx.Table() 41 42 if len(n.Row) != table.ColumnCount() { 43 return nil, errors.New("number of values in row must equal number of columns in the requested table") 44 } 45 46 // Process the Datums within the expressions. 47 var semaCtx tree.SemaContext 48 var rowExprs tree.Exprs 49 for i, expr := range n.Row { 50 colTyp := table.Column(i).DatumType() 51 typedExpr, err := sqlbase.SanitizeVarFreeExpr(d.ctx, expr, colTyp, "range-for-row", &semaCtx, false) 52 if err != nil { 53 return nil, err 54 } 55 if !tree.IsConst(d.evalCtx, typedExpr) { 56 return nil, pgerror.Newf(pgcode.Syntax, "%s: row values must be constant", typedExpr) 57 } 58 datum, err := typedExpr.Eval(d.evalCtx) 59 if err != nil { 60 return nil, errors.Wrapf(err, "%s", typedExpr) 61 } 62 rowExprs = append(rowExprs, datum) 63 } 64 65 idxSpanStart := hex.EncodeToString([]byte(span.Key)) 66 idxSpanEnd := hex.EncodeToString([]byte(span.EndKey)) 67 68 sqltelemetry.IncrementShowCounter(sqltelemetry.RangeForRow) 69 70 // Format the expressions into a string to be passed into the crdb_internal.encode_key function. 71 // We have to be sneaky here and special case when exprs has length 1 and place a comma after the 72 // the single tuple element so that we can deduce the expression actually has a tuple type for 73 // the crdb_internal.encode_key function. 74 // Example: exprs = (1) 75 // Output when used: crdb_internal.encode_key(x, y, (1,)) 76 var fmtCtx tree.FmtCtx 77 fmtCtx.WriteString("(") 78 if len(rowExprs) == 1 { 79 fmtCtx.FormatNode(rowExprs[0]) 80 fmtCtx.WriteString(",") 81 } else { 82 fmtCtx.FormatNode(&rowExprs) 83 } 84 fmtCtx.WriteString(")") 85 rowString := fmtCtx.String() 86 87 const query = ` 88 SELECT 89 CASE WHEN r.start_key < x'%[5]s' THEN NULL ELSE crdb_internal.pretty_key(r.start_key, 2) END AS start_key, 90 CASE WHEN r.end_key >= x'%[6]s' THEN NULL ELSE crdb_internal.pretty_key(r.end_key, 2) END AS end_key, 91 range_id, 92 lease_holder, 93 gossip_nodes.locality as lease_holder_locality, 94 replicas, 95 replica_localities 96 FROM %[4]s.crdb_internal.ranges AS r 97 LEFT JOIN %[4]s.crdb_internal.gossip_nodes ON lease_holder = node_id 98 WHERE (r.start_key <= crdb_internal.encode_key(%[1]d, %[2]d, %[3]s)) 99 AND (r.end_key > crdb_internal.encode_key(%[1]d, %[2]d, %[3]s)) ORDER BY r.start_key 100 ` 101 // note: CatalogName.String() != Catalog() 102 return parse( 103 fmt.Sprintf( 104 query, 105 table.ID(), 106 idx.ID(), 107 rowString, 108 resName.CatalogName.String(), 109 idxSpanStart, 110 idxSpanEnd, 111 ), 112 ) 113 114 }