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()                   {}