Skip to content

Commit

Permalink
sql: add support for virtual schema qualified types
Browse files Browse the repository at this point in the history
Fixes cockroachdb#16395.

Release note (sql change): Allows for referencing static data types
under the `pg_catalog` qualification like `pg_catalog.int`.
  • Loading branch information
rohany committed May 20, 2020
1 parent 09125b5 commit 51d1aad
Show file tree
Hide file tree
Showing 11 changed files with 465 additions and 310 deletions.
2 changes: 2 additions & 0 deletions pkg/sql/execinfrapb/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ func (tr *DistSQLTypeResolver) ResolveTypeByID(id uint32) (*types.T, error) {
switch t := typDesc.Kind; t {
case sqlbase.TypeDescriptor_ENUM:
typ = types.MakeEnum(id)
case sqlbase.TypeDescriptor_ALIAS:
return typDesc.Alias, nil
default:
return nil, errors.AssertionFailedf("unknown type kind %s", t)
}
Expand Down
34 changes: 34 additions & 0 deletions pkg/sql/logical_schema_accessors.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
"github.com/cockroachdb/cockroach/pkg/sql/parser"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
Expand Down Expand Up @@ -85,6 +86,39 @@ func (l *LogicalSchemaAccessor) GetObjectDesc(
) (ObjectDescriptor, error) {
switch flags.DesiredObjectKind {
case tree.TypeObject:
// If the input schema matches a virtual schema, look into it.
if scEntry, ok := l.vt.getVirtualSchemaEntry(schema); ok {
var result ObjectDescriptor
// If the virtual schema actually contains types, then try to find the
// requested type.
if scEntry.containsTypes {
// Currently, we don't allow creation of types in virtual schemas, so
// the only types present in the virtual schemas that have types (i.e.
// pg_catalog) are types that are known at parse time. So, attempt to
// parse the input object as a statically known type. Note that an
// invalid input type like "notatype" will be parsed successfully as
// a ResolvableTypeReference, so the error here does not need to be
// intercepted and inspected.
typRef, err := parser.ParseType(object)
if err != nil {
return nil, err
}
// If the parsed reference is actually a statically known type, then
// we can return it. We return a simple wrapping of this type as
// TypeDescriptor that represents an alias of the result type.
typ, ok := tree.GetStaticallyKnownType(typRef)
if ok {
result = sqlbase.MakeSimpleAliasTypeDescriptor(typ)
}
}
if result == nil {
if flags.Required {
name := tree.MakeNewQualifiedTypeName(db, schema, object)
return nil, sqlbase.NewUndefinedTypeError(&name)
}
}
return result, nil
}
return (UncachedPhysicalAccessor{}).GetObjectDesc(ctx, txn, settings, codec, db, schema, object, flags)
case tree.TableObject:
l.tn = tree.MakeTableNameWithSchema(tree.Name(db), tree.Name(schema), tree.Name(object))
Expand Down
5 changes: 0 additions & 5 deletions pkg/sql/logictest/testdata/logic_test/enums
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ SELECT 'Z'::public.int
----
Z

query T
SELECT 'Z'::"int"
----
Z

statement ok
CREATE TYPE greeting AS ENUM ('hello', 'howdy', 'hi')

Expand Down
15 changes: 15 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/typing
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,18 @@ query T
SELECT max(NULL) FROM (VALUES (NULL), (NULL)) t0(c0)
----
NULL

# Test qualified type references.
query IITR
SELECT 1::pg_catalog.int4, 1::pg_catalog.int8, 'aa'::pg_catalog.text, 4.2::pg_catalog.float4
----
1 1 aa 4.2

# Test that we error out referencing unknown types in pg_catalog.
query error pq: type "pg_catalog.special_int" does not exist
SELECT 1::pg_catalog.special_int

# Test that we error out trying to reference types in schemas that
# don't have types.
query error pq: type "crdb_internal.mytype" does not exist
SELECT 1::crdb_internal.mytype
1 change: 1 addition & 0 deletions pkg/sql/pg_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ var pgCatalog = virtualSchema{
// database set. Simply reject any attempts to use them in that
// case.
validWithNoDatabaseContext: false,
containsTypes: true,
}

// The catalog pg_am stores information about relation access methods.
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ func (p *planner) ResolveType(name *tree.UnresolvedObjectName) (*types.T, error)
// Override the hydrated name with the fully resolved type name.
typ.TypeMeta.Name = &tn
return typ, nil
case sqlbase.TypeDescriptor_ALIAS:
return tdesc.Alias, nil
default:
return nil, errors.AssertionFailedf("unknown type kind %s", t.String())
}
Expand Down
11 changes: 11 additions & 0 deletions pkg/sql/sem/tree/type_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ func MakeTypeNameFromPrefix(prefix ObjectNamePrefix, object Name) TypeName {
}}
}

// MakeNewQualifiedTypeName creates a fully qualified type name.
func MakeNewQualifiedTypeName(db, schema, typ string) TypeName {
return TypeName{objName{
ObjectNamePrefix: ObjectNamePrefix{
CatalogName: Name(db),
SchemaName: Name(schema),
},
ObjectName: Name(typ),
}}
}

// TypeReferenceResolver is the interface that will provide the ability
// to actually look up type metadata and transform references into
// *types.T's.
Expand Down
17 changes: 17 additions & 0 deletions pkg/sql/sqlbase/structured.go
Original file line number Diff line number Diff line change
Expand Up @@ -4169,11 +4169,28 @@ func (desc *TypeDescriptor) HydrateTypeInfo(typ *types.T) error {
PhysicalRepresentations: physical,
}
return nil
case TypeDescriptor_ALIAS:
// This is a noop until we possibly allow aliases to user defined types.
return nil
default:
return errors.AssertionFailedf("unknown type descriptor kind %s", desc.Kind)
}
}

// MakeSimpleAliasTypeDescriptor creates a type descriptor that is an alias
// for the input type. It is intended to be used as an intermediate for name
// resolution, and should not be serialized and stored on disk.
func MakeSimpleAliasTypeDescriptor(typ *types.T) *TypeDescriptor {
return &TypeDescriptor{
ParentID: InvalidID,
ParentSchemaID: InvalidID,
Name: typ.Name(),
ID: InvalidID,
Kind: TypeDescriptor_ALIAS,
Alias: typ,
}
}

// NameResolutionResult implements the NameResolutionResult interface.
func (desc *TypeDescriptor) NameResolutionResult() {}

Expand Down
Loading

0 comments on commit 51d1aad

Please sign in to comment.