323 lines
13 KiB
Go
323 lines
13 KiB
Go
// Copyright 2024 Dolthub, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package types
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
"github.com/lib/pq/oid"
|
|
|
|
"github.com/dolthub/doltgresql/core/id"
|
|
"github.com/dolthub/doltgresql/postgres/parser/types"
|
|
)
|
|
|
|
// TypeAlignment represents the alignment required when storing a value of this type.
|
|
type TypeAlignment string
|
|
|
|
const (
|
|
TypeAlignment_Char TypeAlignment = "c"
|
|
TypeAlignment_Short TypeAlignment = "s"
|
|
TypeAlignment_Int TypeAlignment = "i"
|
|
TypeAlignment_Double TypeAlignment = "d"
|
|
)
|
|
|
|
// TypeCategory represents the type category that a type belongs to. These are used by Postgres to group similar types
|
|
// for parameter resolution, operator resolution, etc.
|
|
type TypeCategory string
|
|
|
|
const (
|
|
TypeCategory_ArrayTypes TypeCategory = "A"
|
|
TypeCategory_BooleanTypes TypeCategory = "B"
|
|
TypeCategory_CompositeTypes TypeCategory = "C"
|
|
TypeCategory_DateTimeTypes TypeCategory = "D"
|
|
TypeCategory_EnumTypes TypeCategory = "E"
|
|
TypeCategory_GeometricTypes TypeCategory = "G"
|
|
TypeCategory_NetworkAddressTypes TypeCategory = "I"
|
|
TypeCategory_NumericTypes TypeCategory = "N"
|
|
TypeCategory_PseudoTypes TypeCategory = "P"
|
|
TypeCategory_RangeTypes TypeCategory = "R"
|
|
TypeCategory_StringTypes TypeCategory = "S"
|
|
TypeCategory_TimespanTypes TypeCategory = "T"
|
|
TypeCategory_UserDefinedTypes TypeCategory = "U"
|
|
TypeCategory_BitStringTypes TypeCategory = "V"
|
|
TypeCategory_UnknownTypes TypeCategory = "X"
|
|
TypeCategory_InternalUseTypes TypeCategory = "Z"
|
|
)
|
|
|
|
// TypeStorage represents the storage strategy for storing `varlena` (typlen = -1) types.
|
|
type TypeStorage string
|
|
|
|
const (
|
|
TypeStorage_Plain TypeStorage = "p"
|
|
TypeStorage_External TypeStorage = "e"
|
|
TypeStorage_Main TypeStorage = "m"
|
|
TypeStorage_Extended TypeStorage = "x"
|
|
)
|
|
|
|
// TypeType represents the type of types that can be created/used.
|
|
// This includes 'base', 'composite', 'domain', 'enum', 'shell', 'range' and 'multirange'.
|
|
type TypeType string
|
|
|
|
const (
|
|
TypeType_Base TypeType = "b"
|
|
TypeType_Composite TypeType = "c"
|
|
TypeType_Domain TypeType = "d"
|
|
TypeType_Enum TypeType = "e"
|
|
TypeType_Pseudo TypeType = "p"
|
|
TypeType_Range TypeType = "r"
|
|
TypeType_MultiRange TypeType = "m"
|
|
)
|
|
|
|
// GetTypeByID returns the DoltgresType matching the given Internal ID.
|
|
// If the Internal ID does not match a type, then nil is returned.
|
|
func GetTypeByID(internalID id.Type) *DoltgresType {
|
|
t, ok := IDToBuiltInDoltgresType[internalID]
|
|
if !ok {
|
|
// TODO: return UNKNOWN?
|
|
return nil
|
|
}
|
|
return t
|
|
}
|
|
|
|
// GetAllBuitInTypes returns a slice containing all registered types.
|
|
// The slice is sorted by each type's ID.
|
|
func GetAllBuitInTypes() []*DoltgresType {
|
|
pgTypes := make([]*DoltgresType, 0, len(IDToBuiltInDoltgresType))
|
|
for internalID, typ := range IDToBuiltInDoltgresType {
|
|
if typ.ID == Unknown.ID && internalID.TypeName() != "unknown" {
|
|
continue
|
|
}
|
|
pgTypes = append(pgTypes, typ)
|
|
}
|
|
sort.Slice(pgTypes, func(i, j int) bool {
|
|
return pgTypes[i].ID < pgTypes[j].ID
|
|
})
|
|
return pgTypes
|
|
}
|
|
|
|
// IDToBuiltInDoltgresType is a map of id.Id to Doltgres' built-in type.
|
|
var IDToBuiltInDoltgresType map[id.Type]*DoltgresType
|
|
|
|
// NameToInternalID is a mapping from a given name to its respective Internal ID.
|
|
var NameToInternalID = map[string]id.Type{}
|
|
|
|
// idToInternalSerializationFunc is a map from the `send` function ID to the internal serialization function.
|
|
var idToInternalSerializationFunc = map[id.Function]internalSerializationFunc{}
|
|
|
|
// idToInternalDeserializationFunc is a map from the `receive` function ID to the internal deserialization function.
|
|
var idToInternalDeserializationFunc = map[id.Function]internalDeserializationFunc{}
|
|
|
|
// init, for now, fills the contents of IDToBuiltInDoltgresType and NameToInternalID, so that we may search for types
|
|
// using regtype. This should be replaced with a better abstraction at some point.
|
|
func init() {
|
|
// For some reason, Go refuses to compile if this map is declared globally.
|
|
// Serialization references functions that eventually reference this map, and this map references all types such
|
|
// that Go thinks there's a reference cycle. It's not a real cycle though since the functions aren't evaluated at
|
|
// compile time, but Go finds an issue with it, so this is a workaround.
|
|
IDToBuiltInDoltgresType = map[id.Type]*DoltgresType{
|
|
toInternal("_abstime"): Unknown,
|
|
toInternal("_aclitem"): Unknown,
|
|
toInternal("_bit"): BitArray,
|
|
toInternal("_bool"): BoolArray,
|
|
toInternal("_box"): Unknown,
|
|
toInternal("_bpchar"): BpCharArray,
|
|
toInternal("_bytea"): ByteaArray,
|
|
toInternal("_char"): InternalCharArray,
|
|
toInternal("_cid"): Unknown,
|
|
toInternal("_cidr"): Unknown,
|
|
toInternal("_circle"): Unknown,
|
|
toInternal("_cstring"): CstringArray,
|
|
toInternal("_date"): DateArray,
|
|
toInternal("_daterange"): Unknown,
|
|
toInternal("_float4"): Float32Array,
|
|
toInternal("_float8"): Float64Array,
|
|
toInternal("_gtsvector"): Unknown,
|
|
toInternal("_inet"): Unknown,
|
|
toInternal("_int2"): Int16Array,
|
|
toInternal("_int2vector"): Int16vectorArray,
|
|
toInternal("_int4"): Int32Array,
|
|
toInternal("_int4range"): Unknown,
|
|
toInternal("_int8"): Int64Array,
|
|
toInternal("_int8range"): Unknown,
|
|
toInternal("_interval"): IntervalArray,
|
|
toInternal("_json"): JsonArray,
|
|
toInternal("_jsonb"): JsonBArray,
|
|
toInternal("_line"): Unknown,
|
|
toInternal("_lseg"): Unknown,
|
|
toInternal("_macaddr"): Unknown,
|
|
toInternal("_money"): Unknown,
|
|
toInternal("_name"): NameArray,
|
|
toInternal("_numeric"): NumericArray,
|
|
toInternal("_numrange"): Unknown,
|
|
toInternal("_oid"): OidArray,
|
|
toInternal("_oidvector"): OidvectorArray,
|
|
toInternal("_path"): Unknown,
|
|
toInternal("_pg_lsn"): Unknown,
|
|
toInternal("_point"): Unknown,
|
|
toInternal("_polygon"): Unknown,
|
|
toInternal("_record"): RecordArray,
|
|
toInternal("_refcursor"): Unknown,
|
|
toInternal("_regclass"): RegclassArray,
|
|
toInternal("_regconfig"): Unknown,
|
|
toInternal("_regdictionary"): Unknown,
|
|
toInternal("_regnamespace"): Unknown,
|
|
toInternal("_regoper"): Unknown,
|
|
toInternal("_regoperator"): Unknown,
|
|
toInternal("_regproc"): RegprocArray,
|
|
toInternal("_regprocedure"): Unknown,
|
|
toInternal("_regrole"): Unknown,
|
|
toInternal("_regtype"): RegtypeArray,
|
|
toInternal("_reltime"): Unknown,
|
|
toInternal("_text"): TextArray,
|
|
toInternal("_tid"): Unknown,
|
|
toInternal("_time"): TimeArray,
|
|
toInternal("_timestamp"): TimestampArray,
|
|
toInternal("_timestamptz"): TimestampTZArray,
|
|
toInternal("_timetz"): TimeTZArray,
|
|
toInternal("_tinterval"): Unknown,
|
|
toInternal("_tsquery"): Unknown,
|
|
toInternal("_tsrange"): Unknown,
|
|
toInternal("_tstzrange"): Unknown,
|
|
toInternal("_tsvector"): Unknown,
|
|
toInternal("_txid_snapshot"): Unknown,
|
|
toInternal("_uuid"): UuidArray,
|
|
toInternal("_varbit"): VarBitArray,
|
|
toInternal("_varchar"): VarCharArray,
|
|
toInternal("_xid"): XidArray,
|
|
toInternal("_xml"): Unknown,
|
|
toInternal("abstime"): Unknown,
|
|
toInternal("aclitem"): Unknown,
|
|
toInternal("any"): Any,
|
|
toInternal("anyarray"): AnyArray,
|
|
toInternal("anyelement"): AnyElement,
|
|
toInternal("anyenum"): AnyEnum,
|
|
toInternal("anynonarray"): AnyNonArray,
|
|
toInternal("anyrange"): Unknown,
|
|
toInternal("bit"): Bit,
|
|
toInternal("bool"): Bool,
|
|
toInternal("box"): Unknown,
|
|
toInternal("bpchar"): BpChar,
|
|
toInternal("bytea"): Bytea,
|
|
toInternal("char"): InternalChar,
|
|
toInternal("cid"): Unknown,
|
|
toInternal("cidr"): Unknown,
|
|
toInternal("circle"): Unknown,
|
|
toInternal("cstring"): Cstring,
|
|
toInternal("date"): Date,
|
|
toInternal("daterange"): Unknown,
|
|
toInternal("event_trigger"): Unknown,
|
|
toInternal("fdw_handler"): Unknown,
|
|
toInternal("float4"): Float32,
|
|
toInternal("float8"): Float64,
|
|
toInternal("gtsvector"): Unknown,
|
|
toInternal("index_am_handler"): Unknown,
|
|
toInternal("inet"): Unknown,
|
|
toInternal("int2"): Int16,
|
|
toInternal("int2vector"): Int16vector,
|
|
toInternal("int4"): Int32,
|
|
toInternal("int4range"): Unknown,
|
|
toInternal("int8"): Int64,
|
|
toInternal("int8range"): Unknown,
|
|
toInternal("internal"): Internal,
|
|
toInternal("interval"): Interval,
|
|
toInternal("json"): Json,
|
|
toInternal("jsonb"): JsonB,
|
|
toInternal("language_handler"): Unknown,
|
|
toInternal("line"): Unknown,
|
|
toInternal("lseg"): Unknown,
|
|
toInternal("macaddr"): Unknown,
|
|
toInternal("money"): Unknown,
|
|
toInternal("name"): Name,
|
|
toInternal("numeric"): Numeric,
|
|
toInternal("numrange"): Unknown,
|
|
toInternal("oid"): Oid,
|
|
toInternal("oidvector"): Oidvector,
|
|
toInternal("opaque"): Unknown,
|
|
toInternal("path"): Unknown,
|
|
toInternal("pg_attribute"): Unknown,
|
|
toInternal("pg_auth_members"): Unknown,
|
|
toInternal("pg_authid"): Unknown,
|
|
toInternal("pg_class"): Unknown,
|
|
toInternal("pg_database"): Unknown,
|
|
toInternal("pg_ddl_command"): Unknown,
|
|
toInternal("pg_lsn"): Unknown,
|
|
toInternal("pg_node_tree"): Unknown,
|
|
toInternal("pg_proc"): Unknown,
|
|
toInternal("pg_shseclabel"): Unknown,
|
|
toInternal("pg_type"): Unknown,
|
|
toInternal("point"): Unknown,
|
|
toInternal("polygon"): Unknown,
|
|
toInternal("record"): Record,
|
|
toInternal("refcursor"): Unknown,
|
|
toInternal("regclass"): Regclass,
|
|
toInternal("regconfig"): Unknown,
|
|
toInternal("regdictionary"): Unknown,
|
|
toInternal("regnamespace"): Unknown,
|
|
toInternal("regoper"): Unknown,
|
|
toInternal("regoperator"): Unknown,
|
|
toInternal("regproc"): Regproc,
|
|
toInternal("regprocedure"): Unknown,
|
|
toInternal("regrole"): Unknown,
|
|
toInternal("regtype"): Regtype,
|
|
toInternal("reltime"): Unknown,
|
|
toInternal("smgr"): Unknown,
|
|
toInternal("text"): Text,
|
|
toInternal("tid"): Unknown,
|
|
toInternal("time"): Time,
|
|
toInternal("timestamp"): Timestamp,
|
|
toInternal("timestamptz"): TimestampTZ,
|
|
toInternal("timetz"): TimeTZ,
|
|
toInternal("tinterval"): Unknown,
|
|
toInternal("trigger"): Trigger,
|
|
toInternal("tsm_handler"): Unknown,
|
|
toInternal("tsquery"): Unknown,
|
|
toInternal("tsrange"): Unknown,
|
|
toInternal("tstzrange"): Unknown,
|
|
toInternal("tsvector"): Unknown,
|
|
toInternal("txid_snapshot"): Unknown,
|
|
toInternal("unknown"): Unknown,
|
|
toInternal("uuid"): Uuid,
|
|
toInternal("varbit"): VarBit,
|
|
toInternal("varchar"): VarChar,
|
|
toInternal("void"): Void,
|
|
toInternal("xid"): Xid,
|
|
toInternal("xml"): Unknown,
|
|
}
|
|
for _, t := range GetAllBuitInTypes() {
|
|
NameToInternalID[t.Name()] = t.ID
|
|
pt, ok := types.OidToType[oid.Oid(id.Cache().ToOID(t.ID.AsId()))]
|
|
if ok {
|
|
NameToInternalID[pt.SQLStandardName()] = t.ID
|
|
}
|
|
if t.SendFunc != 0 && t.SerializationFunc != nil {
|
|
idToInternalSerializationFunc[globalFunctionRegistry.GetInternalID(t.SendFunc)] = t.SerializationFunc
|
|
}
|
|
if t.ReceiveFunc != 0 && t.DeserializationFunc != nil {
|
|
idToInternalDeserializationFunc[globalFunctionRegistry.GetInternalID(t.ReceiveFunc)] = t.DeserializationFunc
|
|
}
|
|
}
|
|
// Add the created types to the deserialization map
|
|
idToInternalDeserializationFunc[globalFunctionRegistry.GetInternalID(toFuncID("domain_recv", toInternal("internal"), toInternal("oid"), toInternal("int4")))] = deserializeTypeDomain
|
|
idToInternalDeserializationFunc[globalFunctionRegistry.GetInternalID(toFuncID("enum_recv", toInternal("internal"), toInternal("oid")))] = deserializeTypeEnum
|
|
// Add the created types to the serialization map
|
|
idToInternalSerializationFunc[globalFunctionRegistry.GetInternalID(toFuncID("enum_send", toInternal("anyenum")))] = serializeTypeEnum
|
|
}
|
|
|
|
// ErrCastOutOfRange is returned when a value is out of range for a given cast function.
|
|
// We use this error type as a sentinel error when a type conversion function fails only due to the range of the
|
|
// input in order to conform to expectations in go-mysql-server.
|
|
var ErrCastOutOfRange = errors.New("out of range")
|