// 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")