github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/create_type.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 sql 12 13 import ( 14 "context" 15 "fmt" 16 17 "github.com/cockroachdb/cockroach/pkg/clusterversion" 18 "github.com/cockroachdb/cockroach/pkg/keys" 19 "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv" 20 "github.com/cockroachdb/cockroach/pkg/sql/enum" 21 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 22 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 23 "github.com/cockroachdb/cockroach/pkg/sql/privilege" 24 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 25 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 26 "github.com/cockroachdb/cockroach/pkg/sql/types" 27 "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" 28 "github.com/cockroachdb/errors" 29 ) 30 31 type createTypeNode struct { 32 n *tree.CreateType 33 } 34 35 // Use to satisfy the linter. 36 var _ planNode = &createTypeNode{n: nil} 37 38 func (p *planner) CreateType(ctx context.Context, n *tree.CreateType) (planNode, error) { 39 return &createTypeNode{n: n}, nil 40 } 41 42 func (n *createTypeNode) startExec(params runParams) error { 43 switch n.n.Variety { 44 case tree.Enum: 45 return params.p.createEnum(params, n.n) 46 default: 47 return unimplemented.NewWithIssue(25123, "CREATE TYPE") 48 } 49 } 50 51 func resolveNewTypeName( 52 params runParams, name *tree.UnresolvedObjectName, 53 ) (*tree.TypeName, *DatabaseDescriptor, error) { 54 // Resolve the target schema and database. 55 db, prefix, err := params.p.ResolveUncachedDatabase(params.ctx, name) 56 if err != nil { 57 return nil, nil, err 58 } 59 60 if err := params.p.CheckPrivilege(params.ctx, db, privilege.CREATE); err != nil { 61 return nil, nil, err 62 } 63 64 // Disallow type creation in the system database. 65 if db.ID == keys.SystemDatabaseID { 66 return nil, nil, errors.New("cannot create a type in the system database") 67 } 68 69 typename := tree.NewUnqualifiedTypeName(tree.Name(name.Object())) 70 typename.ObjectNamePrefix = prefix 71 return typename, db, nil 72 } 73 74 // getCreateTypeParams performs some initial validation on the input new 75 // TypeName and returns the key for the new type descriptor, the ID of the 76 // new type, the parent database and parent schema id. 77 func getCreateTypeParams( 78 params runParams, name *tree.TypeName, db *DatabaseDescriptor, 79 ) (sqlbase.DescriptorKey, sqlbase.ID, error) { 80 // TODO (rohany): This should be named object key. 81 typeKey := sqlbase.MakePublicTableNameKey(params.ctx, params.ExecCfg().Settings, db.ID, name.Type()) 82 // As of now, we can only create types in the public schema. 83 schemaID := sqlbase.ID(keys.PublicSchemaID) 84 exists, collided, err := sqlbase.LookupObjectID( 85 params.ctx, params.p.txn, params.ExecCfg().Codec, db.ID, schemaID, name.Type()) 86 if err == nil && exists { 87 // Try and see what kind of object we collided with. 88 desc, err := catalogkv.GetDescriptorByID(params.ctx, params.p.txn, params.ExecCfg().Codec, collided) 89 if err != nil { 90 return nil, 0, err 91 } 92 return nil, 0, makeObjectAlreadyExistsError(desc, name.String()) 93 } 94 if err != nil { 95 return nil, 0, err 96 } 97 id, err := catalogkv.GenerateUniqueDescID(params.ctx, params.ExecCfg().DB, params.ExecCfg().Codec) 98 if err != nil { 99 return nil, 0, err 100 } 101 return typeKey, id, nil 102 } 103 104 // createArrayType performs the implicit array type creation logic of Postgres. 105 // When a type is created in Postgres, Postgres will implicitly create an array 106 // type of that user defined type. This array type tracks changes to the 107 // original type, and is dropped when the original type is dropped. 108 // createArrayType creates the implicit array type for the input TypeDescriptor 109 // and returns the ID of the created type. 110 func (p *planner) createArrayType( 111 params runParams, 112 n *tree.CreateType, 113 typ *tree.TypeName, 114 typDesc *sqlbase.MutableTypeDescriptor, 115 db *DatabaseDescriptor, 116 ) (sqlbase.ID, error) { 117 // Postgres starts off trying to create the type as _<typename>. It then 118 // continues adding "_" to the front of the name until it doesn't find 119 // a collision. 120 schemaID := sqlbase.ID(keys.PublicSchemaID) 121 arrayTypeName := "_" + typ.Type() 122 var arrayTypeKey sqlbase.DescriptorKey 123 for { 124 // See if there is a collision with the current name. 125 exists, _, err := sqlbase.LookupObjectID( 126 params.ctx, 127 params.p.txn, 128 params.ExecCfg().Codec, 129 db.ID, 130 schemaID, 131 arrayTypeName, 132 ) 133 if err != nil { 134 return 0, err 135 } 136 // If we found an empty spot, then create the namespace key for this entry. 137 if !exists { 138 arrayTypeKey = sqlbase.MakePublicTableNameKey( 139 params.ctx, 140 params.ExecCfg().Settings, 141 db.ID, 142 arrayTypeName, 143 ) 144 break 145 } 146 // Otherwise, append another "_" to the front of the name. 147 arrayTypeName = "_" + arrayTypeName 148 } 149 150 // Generate the stable ID for the array type. 151 id, err := catalogkv.GenerateUniqueDescID(params.ctx, params.ExecCfg().DB, params.ExecCfg().Codec) 152 if err != nil { 153 return 0, err 154 } 155 156 // Create the element type for the array. Note that it must know about the 157 // ID of the array type in order for the array type to correctly created. 158 var elemTyp *types.T 159 switch t := typDesc.Kind; t { 160 case sqlbase.TypeDescriptor_ENUM: 161 elemTyp = types.MakeEnum(uint32(typDesc.ID), uint32(id)) 162 default: 163 return 0, errors.AssertionFailedf("cannot make array type for kind %s", t.String()) 164 } 165 166 // Construct the descriptor for the array type. 167 arrayTypDesc := sqlbase.NewMutableCreatedTypeDescriptor(sqlbase.MakeTypeDescriptor( 168 db.ID, keys.PublicSchemaID, id, arrayTypeName, 169 )) 170 arrayTypDesc.Kind = sqlbase.TypeDescriptor_ALIAS 171 arrayTypDesc.Alias = types.MakeArray(elemTyp) 172 173 jobStr := fmt.Sprintf("implicit array type creation for %s", tree.AsStringWithFQNames(n, params.Ann())) 174 if err := p.createDescriptorWithID( 175 params.ctx, 176 arrayTypeKey.Key(params.ExecCfg().Codec), 177 id, 178 arrayTypDesc, 179 params.EvalContext().Settings, 180 jobStr, 181 ); err != nil { 182 return 0, err 183 } 184 return id, nil 185 } 186 187 func (p *planner) createEnum(params runParams, n *tree.CreateType) error { 188 // Make sure that all nodes in the cluster are able to recognize ENUM types. 189 if !p.ExecCfg().Settings.Version.IsActive(params.ctx, clusterversion.VersionEnums) { 190 return pgerror.Newf(pgcode.FeatureNotSupported, 191 "not all nodes are the correct version for ENUM type creation") 192 } 193 194 // Check that usage of ENUM types is enabled. 195 if !p.EvalContext().SessionData.EnumsEnabled { 196 return pgerror.Newf(pgcode.FeatureNotSupported, 197 "session variable experimental_enable_enums is set to false, cannot create an enum") 198 } 199 200 // Ensure there are no duplicates in the input enum values. 201 seenVals := make(map[string]struct{}) 202 for _, value := range n.EnumLabels { 203 _, ok := seenVals[value] 204 if ok { 205 return pgerror.Newf(pgcode.InvalidObjectDefinition, 206 "enum definition contains duplicate value %q", value) 207 } 208 seenVals[value] = struct{}{} 209 } 210 211 // Resolve the desired new type name. 212 typeName, db, err := resolveNewTypeName(params, n.TypeName) 213 if err != nil { 214 return err 215 } 216 n.TypeName.SetAnnotation(&p.semaCtx.Annotations, typeName) 217 218 // Generate a key in the namespace table and a new id for this type. 219 typeKey, id, err := getCreateTypeParams(params, typeName, db) 220 if err != nil { 221 return err 222 } 223 224 members := make([]sqlbase.TypeDescriptor_EnumMember, len(n.EnumLabels)) 225 physReps := enum.GenerateNEvenlySpacedBytes(len(n.EnumLabels)) 226 for i := range n.EnumLabels { 227 members[i] = sqlbase.TypeDescriptor_EnumMember{ 228 LogicalRepresentation: n.EnumLabels[i], 229 PhysicalRepresentation: physReps[i], 230 } 231 } 232 233 // TODO (rohany): OID's are computed using an offset of 234 // oidext.CockroachPredefinedOIDMax from the descriptor ID. Once we have 235 // a free list of descriptor ID's (#48438), we should allocate an ID from 236 // there if id + oidext.CockroachPredefinedOIDMax overflows past the 237 // maximum uint32 value. 238 typeDesc := sqlbase.NewMutableCreatedTypeDescriptor(sqlbase.MakeTypeDescriptor( 239 db.ID, keys.PublicSchemaID, id, typeName.Type(), 240 )) 241 typeDesc.Kind = sqlbase.TypeDescriptor_ENUM 242 typeDesc.EnumMembers = members 243 244 // Create the implicit array type for this type before finishing the type. 245 arrayTypeID, err := p.createArrayType(params, n, typeName, typeDesc, db) 246 if err != nil { 247 return err 248 } 249 250 // Update the typeDesc with the created array type ID. 251 typeDesc.ArrayTypeID = arrayTypeID 252 253 // Now create the type after the implicit array type as been created. 254 return p.createDescriptorWithID( 255 params.ctx, 256 typeKey.Key(params.ExecCfg().Codec), 257 id, 258 typeDesc, 259 params.EvalContext().Settings, 260 tree.AsStringWithFQNames(n, params.Ann()), 261 ) 262 } 263 264 func (n *createTypeNode) Next(params runParams) (bool, error) { return false, nil } 265 func (n *createTypeNode) Values() tree.Datums { return tree.Datums{} } 266 func (n *createTypeNode) Close(ctx context.Context) {} 267 func (n *createTypeNode) ReadingOwnWrites() {}