github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/schemaexpr/column.go (about) 1 // Copyright 2020 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 schemaexpr 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/sql/parser" 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/sqlbase" 21 "github.com/cockroachdb/cockroach/pkg/sql/types" 22 ) 23 24 // DequalifyColumnRefs returns an expression with database nad table names 25 // stripped from qualified column names. 26 // 27 // For example: 28 // 29 // tab.a > 0 AND db.tab.b = 'foo' 30 // => 31 // a > 0 AND b = 'foo' 32 // 33 // This dequalification is necessary when CHECK constraints, computed columns, 34 // or partial index predicates are created. If the table name was not stripped, 35 // these expressions would become invalid if the table is renamed. 36 func DequalifyColumnRefs( 37 ctx context.Context, source *sqlbase.DataSourceInfo, expr tree.Expr, 38 ) (tree.Expr, error) { 39 resolver := sqlbase.ColumnResolver{Source: source} 40 return tree.SimpleVisit( 41 expr, 42 func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) { 43 if vBase, ok := expr.(tree.VarName); ok { 44 v, err := vBase.NormalizeVarName() 45 if err != nil { 46 return false, nil, err 47 } 48 if c, ok := v.(*tree.ColumnItem); ok { 49 _, err := c.Resolve(ctx, &resolver) 50 if err != nil { 51 return false, nil, err 52 } 53 colIdx := resolver.ResolverState.ColIdx 54 col := source.SourceColumns[colIdx] 55 return false, &tree.ColumnItem{ColumnName: tree.Name(col.Name)}, nil 56 } 57 } 58 return true, expr, err 59 }, 60 ) 61 } 62 63 // iterColDescriptors iterates over the expression's variable columns and 64 // calls f on each. 65 // 66 // If the expression references a column that does not exist in the table 67 // descriptor, iterColDescriptors errs with pgcode.UndefinedColumn. 68 func iterColDescriptors( 69 desc *sqlbase.MutableTableDescriptor, rootExpr tree.Expr, f func(*sqlbase.ColumnDescriptor) error, 70 ) error { 71 _, err := tree.SimpleVisit(rootExpr, func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) { 72 vBase, ok := expr.(tree.VarName) 73 if !ok { 74 // Not a VarName, don't do anything to this node. 75 return true, expr, nil 76 } 77 78 v, err := vBase.NormalizeVarName() 79 if err != nil { 80 return false, nil, err 81 } 82 83 c, ok := v.(*tree.ColumnItem) 84 if !ok { 85 return true, expr, nil 86 } 87 88 col, dropped, err := desc.FindColumnByName(c.ColumnName) 89 if err != nil || dropped { 90 return false, nil, pgerror.Newf(pgcode.UndefinedColumn, 91 "column %q does not exist, referenced in %q", c.ColumnName, rootExpr.String()) 92 } 93 94 if err := f(col); err != nil { 95 return false, nil, err 96 } 97 return false, expr, err 98 }) 99 100 return err 101 } 102 103 // DeserializeTableDescExpr takes in a serialized expression and a table, and 104 // returns an expression that has all user defined types resolved for 105 // formatting. It is intended to be used when displaying a serialized 106 // expression within a TableDescriptor. For example, a DEFAULT expression 107 // of a table containing a user defined type t with id 50 would have all 108 // references to t replaced with the id 50. In order to display this expression 109 // back to an end user, the serialized id 50 needs to be replaced back with t. 110 // DeserializeTableDescExpr performs this logic, but only returns a 111 // tree.Expr to be clear that these returned expressions are not safe to Eval. 112 func DeserializeTableDescExpr( 113 ctx context.Context, semaCtx *tree.SemaContext, desc *sqlbase.TableDescriptor, exprStr string, 114 ) (tree.Expr, error) { 115 expr, err := parser.ParseExpr(exprStr) 116 if err != nil { 117 return nil, err 118 } 119 expr, _, err = desc.ReplaceColumnVarsInExprWithDummies(expr) 120 if err != nil { 121 return nil, err 122 } 123 typed, err := expr.TypeCheck(ctx, semaCtx, types.Any) 124 if err != nil { 125 return nil, err 126 } 127 return typed, nil 128 } 129 130 // FormatColumnForDisplay formats a column descriptor as a SQL string, and displays 131 // user defined types in serialized expressions with human friendly formatting. 132 func FormatColumnForDisplay( 133 ctx context.Context, 134 semaCtx *tree.SemaContext, 135 tbl *sqlbase.TableDescriptor, 136 desc *sqlbase.ColumnDescriptor, 137 ) (string, error) { 138 f := tree.NewFmtCtx(tree.FmtSimple) 139 f.FormatNameP(&desc.Name) 140 f.WriteByte(' ') 141 f.WriteString(desc.Type.SQLString()) 142 if desc.Nullable { 143 f.WriteString(" NULL") 144 } else { 145 f.WriteString(" NOT NULL") 146 } 147 if desc.DefaultExpr != nil { 148 f.WriteString(" DEFAULT ") 149 typed, err := DeserializeTableDescExpr(ctx, semaCtx, tbl, *desc.DefaultExpr) 150 if err != nil { 151 return "", err 152 } 153 f.WriteString(tree.SerializeForDisplay(typed)) 154 } 155 if desc.IsComputed() { 156 f.WriteString(" AS (") 157 typed, err := DeserializeTableDescExpr(ctx, semaCtx, tbl, *desc.ComputeExpr) 158 if err != nil { 159 return "", err 160 } 161 f.WriteString(tree.SerializeForDisplay(typed)) 162 f.WriteString(") STORED") 163 } 164 return f.CloseAndGetString(), nil 165 }