using System;
using System.Data;
using Npgsql;
using Npgsql.Internal.Postgres;
using static Npgsql.Util.Statics;
#pragma warning disable CA1720
// ReSharper disable once CheckNamespace
namespace NpgsqlTypes;
///
/// Represents a PostgreSQL data type that can be written or read to the database.
/// Used in places such as to unambiguously specify
/// how to encode or decode values.
///
///
/// See https://www.postgresql.org/docs/current/static/datatype.html.
///
// Source for PG OIDs:
public enum NpgsqlDbType
{
// Note that it's important to never change the numeric values of this enum, since user applications
// compile them in.
#region Numeric Types
///
/// Corresponds to the PostgreSQL 8-byte "bigint" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-numeric.html
Bigint = 1,
///
/// Corresponds to the PostgreSQL 8-byte floating-point "double" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-numeric.html
Double = 8,
///
/// Corresponds to the PostgreSQL 4-byte "integer" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-numeric.html
Integer = 9,
///
/// Corresponds to the PostgreSQL arbitrary-precision "numeric" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-numeric.html
Numeric = 13,
///
/// Corresponds to the PostgreSQL floating-point "real" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-numeric.html
Real = 17,
///
/// Corresponds to the PostgreSQL 2-byte "smallint" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-numeric.html
Smallint = 18,
///
/// Corresponds to the PostgreSQL "money" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-money.html
Money = 12,
#endregion
#region Boolean Type
///
/// Corresponds to the PostgreSQL "boolean" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-boolean.html
Boolean = 2,
#endregion
#region Geometric types
///
/// Corresponds to the PostgreSQL geometric "box" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
Box = 3,
///
/// Corresponds to the PostgreSQL geometric "circle" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
Circle = 5,
///
/// Corresponds to the PostgreSQL geometric "line" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
Line = 10,
///
/// Corresponds to the PostgreSQL geometric "lseg" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
LSeg = 11,
///
/// Corresponds to the PostgreSQL geometric "path" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
Path = 14,
///
/// Corresponds to the PostgreSQL geometric "point" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
Point = 15,
///
/// Corresponds to the PostgreSQL geometric "polygon" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-geometric.html
Polygon = 16,
///
/// Corresponds to the PostgreSQL "cube" type, a geometric type representing multi-dimensional cubes.
///
/// See https://www.postgresql.org/docs/current/cube.html
Cube = 63, // Extension type
#endregion
#region Character Types
///
/// Corresponds to the PostgreSQL "char(n)" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-character.html
Char = 6,
///
/// Corresponds to the PostgreSQL "text" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-character.html
Text = 19,
///
/// Corresponds to the PostgreSQL "varchar" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-character.html
Varchar = 22,
///
/// Corresponds to the PostgreSQL internal "name" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-character.html
Name = 32,
///
/// Corresponds to the PostgreSQL "citext" type for the citext module.
///
/// See https://www.postgresql.org/docs/current/static/citext.html
Citext = 51, // Extension type
///
/// Corresponds to the PostgreSQL "char" type.
///
///
/// This is an internal field and should normally not be used for regular applications.
///
/// See https://www.postgresql.org/docs/current/static/datatype-text.html
///
InternalChar = 38,
#endregion
#region Binary Data Types
///
/// Corresponds to the PostgreSQL "bytea" type, holding a raw byte string.
///
/// See https://www.postgresql.org/docs/current/static/datatype-binary.html
Bytea = 4,
#endregion
#region Date/Time Types
///
/// Corresponds to the PostgreSQL "date" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
Date = 7,
///
/// Corresponds to the PostgreSQL "time" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
Time = 20,
///
/// Corresponds to the PostgreSQL "timestamp" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
Timestamp = 21,
///
/// Corresponds to the PostgreSQL "timestamp with time zone" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
TimestampTz = 26,
///
/// Corresponds to the PostgreSQL "interval" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
Interval = 30,
///
/// Corresponds to the PostgreSQL "time with time zone" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
TimeTz = 31,
///
/// Corresponds to the obsolete PostgreSQL "abstime" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-datetime.html
[Obsolete("The PostgreSQL abstime time is obsolete.")]
Abstime = 33,
#endregion
#region Network Address Types
///
/// Corresponds to the PostgreSQL "inet" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-net-types.html
Inet = 24,
///
/// Corresponds to the PostgreSQL "cidr" type, a field storing an IPv4 or IPv6 network.
///
/// See https://www.postgresql.org/docs/current/static/datatype-net-types.html
Cidr = 44,
///
/// Corresponds to the PostgreSQL "macaddr" type, a field storing a 6-byte physical address.
///
/// See https://www.postgresql.org/docs/current/static/datatype-net-types.html
MacAddr = 34,
///
/// Corresponds to the PostgreSQL "macaddr8" type, a field storing a 6-byte or 8-byte physical address.
///
/// See https://www.postgresql.org/docs/current/static/datatype-net-types.html
MacAddr8 = 54,
#endregion
#region Bit String Types
///
/// Corresponds to the PostgreSQL "bit" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-bit.html
Bit = 25,
///
/// Corresponds to the PostgreSQL "varbit" type, a field storing a variable-length string of bits.
///
/// See https://www.postgresql.org/docs/current/static/datatype-boolean.html
Varbit = 39,
#endregion
#region Text Search Types
///
/// Corresponds to the PostgreSQL "tsvector" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-textsearch.html
TsVector = 45,
///
/// Corresponds to the PostgreSQL "tsquery" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-textsearch.html
TsQuery = 46,
///
/// Corresponds to the PostgreSQL "regconfig" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-textsearch.html
Regconfig = 56,
#endregion
#region UUID Type
///
/// Corresponds to the PostgreSQL "uuid" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-uuid.html
Uuid = 27,
#endregion
#region XML Type
///
/// Corresponds to the PostgreSQL "xml" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-xml.html
Xml = 28,
#endregion
#region JSON Types
///
/// Corresponds to the PostgreSQL "json" type, a field storing JSON in text format.
///
/// See https://www.postgresql.org/docs/current/static/datatype-json.html
///
Json = 35,
///
/// Corresponds to the PostgreSQL "jsonb" type, a field storing JSON in an optimized binary.
/// format.
///
///
/// Supported since PostgreSQL 9.4.
/// See https://www.postgresql.org/docs/current/static/datatype-json.html
///
Jsonb = 36,
///
/// Corresponds to the PostgreSQL "jsonpath" type, a field storing JSON path in text format.
/// format.
///
///
/// Supported since PostgreSQL 12.
/// See https://www.postgresql.org/docs/current/datatype-json.html#DATATYPE-JSONPATH
///
JsonPath = 57,
#endregion
#region HSTORE Type
///
/// Corresponds to the PostgreSQL "hstore" type, a dictionary of string key-value pairs.
///
/// See https://www.postgresql.org/docs/current/static/hstore.html
Hstore = 37, // Extension type
#endregion
#region Internal Types
///
/// Corresponds to the PostgreSQL "refcursor" type.
///
Refcursor = 23,
///
/// Corresponds to the PostgreSQL internal "oidvector" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-oid.html
Oidvector = 29,
///
/// Corresponds to the PostgreSQL internal "int2vector" type.
///
Int2Vector = 52,
///
/// Corresponds to the PostgreSQL "oid" type.
///
/// See https://www.postgresql.org/docs/current/static/datatype-oid.html
Oid = 41,
///
/// Corresponds to the PostgreSQL "xid" type, an internal transaction identifier.
///
/// See https://www.postgresql.org/docs/current/static/datatype-oid.html
Xid = 42,
///
/// Corresponds to the PostgreSQL "xid8" type, an internal transaction identifier.
///
/// See https://www.postgresql.org/docs/current/static/datatype-oid.html
Xid8 = 64,
///
/// Corresponds to the PostgreSQL "cid" type, an internal command identifier.
///
/// See https://www.postgresql.org/docs/current/static/datatype-oid.html
Cid = 43,
///
/// Corresponds to the PostgreSQL "regtype" type, a numeric (OID) ID of a type in the pg_type table.
///
Regtype = 49,
///
/// Corresponds to the PostgreSQL "tid" type, a tuple id identifying the physical location of a row within its table.
///
Tid = 53,
///
/// Corresponds to the PostgreSQL "pg_lsn" type, which can be used to store LSN (Log Sequence Number) data which
/// is a pointer to a location in the WAL.
///
///
/// See: https://www.postgresql.org/docs/current/datatype-pg-lsn.html and
/// https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=7d03a83f4d0736ba869fa6f93973f7623a27038a
///
PgLsn = 59,
#endregion
#region Special
///
/// A special value that can be used to send parameter values to the database without
/// specifying their type, allowing the database to cast them to another value based on context.
/// The value will be converted to a string and send as text.
///
///
/// This value shouldn't ordinarily be used, and makes sense only when sending a data type
/// unsupported by Npgsql.
///
Unknown = 40,
#endregion
#region PostGIS
///
/// The geometry type for PostgreSQL spatial extension PostGIS.
///
Geometry = 50, // Extension type
///
/// The geography (geodetic) type for PostgreSQL spatial extension PostGIS.
///
Geography = 55, // Extension type
#endregion
#region Label tree types
///
/// The PostgreSQL ltree type, each value is a label path "a.label.tree.value", forming a tree in a set.
///
/// See https://www.postgresql.org/docs/current/static/ltree.html
LTree = 60, // Extension type
///
/// The PostgreSQL lquery type for PostgreSQL extension ltree
///
/// See https://www.postgresql.org/docs/current/static/ltree.html
LQuery = 61, // Extension type
///
/// The PostgreSQL ltxtquery type for PostgreSQL extension ltree
///
/// See https://www.postgresql.org/docs/current/static/ltree.html
LTxtQuery = 62, // Extension type
#endregion
#region Range types
///
/// Corresponds to the PostgreSQL "int4range" type.
///
IntegerRange = Range | Integer,
///
/// Corresponds to the PostgreSQL "int8range" type.
///
BigIntRange = Range | Bigint,
///
/// Corresponds to the PostgreSQL "numrange" type.
///
NumericRange = Range | Numeric,
///
/// Corresponds to the PostgreSQL "tsrange" type.
///
TimestampRange = Range | Timestamp,
///
/// Corresponds to the PostgreSQL "tstzrange" type.
///
TimestampTzRange = Range | TimestampTz,
///
/// Corresponds to the PostgreSQL "daterange" type.
///
DateRange = Range | Date,
#endregion Range types
#region Multirange types
///
/// Corresponds to the PostgreSQL "int4multirange" type.
///
IntegerMultirange = Multirange | Integer,
///
/// Corresponds to the PostgreSQL "int8multirange" type.
///
BigIntMultirange = Multirange | Bigint,
///
/// Corresponds to the PostgreSQL "nummultirange" type.
///
NumericMultirange = Multirange | Numeric,
///
/// Corresponds to the PostgreSQL "tsmultirange" type.
///
TimestampMultirange = Multirange | Timestamp,
///
/// Corresponds to the PostgreSQL "tstzmultirange" type.
///
TimestampTzMultirange = Multirange | TimestampTz,
///
/// Corresponds to the PostgreSQL "datemultirange" type.
///
DateMultirange = Multirange | Date,
#endregion Multirange types
#region Composables
///
/// Corresponds to the PostgreSQL "array" type, a variable-length multidimensional array of
/// another type. This value must be combined with another value from
/// via a bit OR (e.g. NpgsqlDbType.Array | NpgsqlDbType.Integer)
///
/// See https://www.postgresql.org/docs/current/static/arrays.html
Array = int.MinValue,
///
/// Corresponds to the PostgreSQL "range" type, continuous range of values of specific type.
/// This value must be combined with another value from
/// via a bit OR (e.g. NpgsqlDbType.Range | NpgsqlDbType.Integer)
///
///
/// Supported since PostgreSQL 9.2.
/// See https://www.postgresql.org/docs/current/static/rangetypes.html
///
Range = 0x40000000,
///
/// Corresponds to the PostgreSQL "multirange" type, continuous range of values of specific type.
/// This value must be combined with another value from
/// via a bit OR (e.g. NpgsqlDbType.Multirange | NpgsqlDbType.Integer)
///
///
/// Supported since PostgreSQL 14.
/// See https://www.postgresql.org/docs/current/static/rangetypes.html
///
Multirange = 0x20000000,
#endregion
}
static class NpgsqlDbTypeExtensions
{
internal static NpgsqlDbType? ToNpgsqlDbType(this DbType dbType)
=> dbType switch
{
DbType.AnsiString => NpgsqlDbType.Text,
DbType.Binary => NpgsqlDbType.Bytea,
DbType.Byte => NpgsqlDbType.Smallint,
DbType.Boolean => NpgsqlDbType.Boolean,
DbType.Currency => NpgsqlDbType.Money,
DbType.Date => NpgsqlDbType.Date,
DbType.DateTime => LegacyTimestampBehavior ? NpgsqlDbType.Timestamp : NpgsqlDbType.TimestampTz,
DbType.Decimal => NpgsqlDbType.Numeric,
DbType.VarNumeric => NpgsqlDbType.Numeric,
DbType.Double => NpgsqlDbType.Double,
DbType.Guid => NpgsqlDbType.Uuid,
DbType.Int16 => NpgsqlDbType.Smallint,
DbType.Int32 => NpgsqlDbType.Integer,
DbType.Int64 => NpgsqlDbType.Bigint,
DbType.Single => NpgsqlDbType.Real,
DbType.String => NpgsqlDbType.Text,
DbType.Time => NpgsqlDbType.Time,
DbType.AnsiStringFixedLength => NpgsqlDbType.Text,
DbType.StringFixedLength => NpgsqlDbType.Text,
DbType.Xml => NpgsqlDbType.Xml,
DbType.DateTime2 => NpgsqlDbType.Timestamp,
DbType.DateTimeOffset => NpgsqlDbType.TimestampTz,
DbType.Object => null,
DbType.SByte => null,
DbType.UInt16 => null,
DbType.UInt32 => null,
DbType.UInt64 => null,
_ => throw new ArgumentOutOfRangeException(nameof(dbType), dbType, null)
};
public static DbType ToDbType(this NpgsqlDbType npgsqlDbType)
=> npgsqlDbType switch
{
// Numeric types
NpgsqlDbType.Smallint => DbType.Int16,
NpgsqlDbType.Integer => DbType.Int32,
NpgsqlDbType.Bigint => DbType.Int64,
NpgsqlDbType.Real => DbType.Single,
NpgsqlDbType.Double => DbType.Double,
NpgsqlDbType.Numeric => DbType.Decimal,
NpgsqlDbType.Money => DbType.Currency,
// Text types
NpgsqlDbType.Text => DbType.String,
NpgsqlDbType.Xml => DbType.Xml,
NpgsqlDbType.Varchar => DbType.String,
NpgsqlDbType.Char => DbType.String,
NpgsqlDbType.Name => DbType.String,
NpgsqlDbType.Citext => DbType.String,
NpgsqlDbType.Refcursor => DbType.Object,
NpgsqlDbType.Jsonb => DbType.Object,
NpgsqlDbType.Json => DbType.Object,
NpgsqlDbType.JsonPath => DbType.Object,
// Date/time types
NpgsqlDbType.Timestamp => LegacyTimestampBehavior ? DbType.DateTime : DbType.DateTime2,
NpgsqlDbType.TimestampTz => LegacyTimestampBehavior ? DbType.DateTimeOffset : DbType.DateTime,
NpgsqlDbType.Date => DbType.Date,
NpgsqlDbType.Time => DbType.Time,
// Misc data types
NpgsqlDbType.Bytea => DbType.Binary,
NpgsqlDbType.Boolean => DbType.Boolean,
NpgsqlDbType.Uuid => DbType.Guid,
NpgsqlDbType.Unknown => DbType.Object,
_ => DbType.Object
};
/// Can return null when a custom range type is used.
internal static string? ToUnqualifiedDataTypeName(this NpgsqlDbType npgsqlDbType)
=> npgsqlDbType switch
{
// Numeric types
NpgsqlDbType.Smallint => "int2",
NpgsqlDbType.Integer => "int4",
NpgsqlDbType.Bigint => "int8",
NpgsqlDbType.Real => "float4",
NpgsqlDbType.Double => "float8",
NpgsqlDbType.Numeric => "numeric",
NpgsqlDbType.Money => "money",
// Text types
NpgsqlDbType.Text => "text",
NpgsqlDbType.Xml => "xml",
NpgsqlDbType.Varchar => "varchar",
NpgsqlDbType.Char => "bpchar",
NpgsqlDbType.Name => "name",
NpgsqlDbType.Refcursor => "refcursor",
NpgsqlDbType.Jsonb => "jsonb",
NpgsqlDbType.Json => "json",
NpgsqlDbType.JsonPath => "jsonpath",
// Date/time types
NpgsqlDbType.Timestamp => "timestamp",
NpgsqlDbType.TimestampTz => "timestamptz",
NpgsqlDbType.Date => "date",
NpgsqlDbType.Time => "time",
NpgsqlDbType.TimeTz => "timetz",
NpgsqlDbType.Interval => "interval",
// Network types
NpgsqlDbType.Cidr => "cidr",
NpgsqlDbType.Inet => "inet",
NpgsqlDbType.MacAddr => "macaddr",
NpgsqlDbType.MacAddr8 => "macaddr8",
// Full-text search types
NpgsqlDbType.TsQuery => "tsquery",
NpgsqlDbType.TsVector => "tsvector",
// Geometry types
NpgsqlDbType.Box => "box",
NpgsqlDbType.Circle => "circle",
NpgsqlDbType.Line => "line",
NpgsqlDbType.LSeg => "lseg",
NpgsqlDbType.Path => "path",
NpgsqlDbType.Point => "point",
NpgsqlDbType.Polygon => "polygon",
// UInt types
NpgsqlDbType.Oid => "oid",
NpgsqlDbType.Xid => "xid",
NpgsqlDbType.Xid8 => "xid8",
NpgsqlDbType.Cid => "cid",
NpgsqlDbType.Regtype => "regtype",
NpgsqlDbType.Regconfig => "regconfig",
// Misc types
NpgsqlDbType.Boolean => "bool",
NpgsqlDbType.Bytea => "bytea",
NpgsqlDbType.Uuid => "uuid",
NpgsqlDbType.Varbit => "varbit",
NpgsqlDbType.Bit => "bit",
// Built-in range types
NpgsqlDbType.IntegerRange => "int4range",
NpgsqlDbType.BigIntRange => "int8range",
NpgsqlDbType.NumericRange => "numrange",
NpgsqlDbType.TimestampRange => "tsrange",
NpgsqlDbType.TimestampTzRange => "tstzrange",
NpgsqlDbType.DateRange => "daterange",
// Built-in multirange types
NpgsqlDbType.IntegerMultirange => "int4multirange",
NpgsqlDbType.BigIntMultirange => "int8multirange",
NpgsqlDbType.NumericMultirange => "nummultirange",
NpgsqlDbType.TimestampMultirange => "tsmultirange",
NpgsqlDbType.TimestampTzMultirange => "tstzmultirange",
NpgsqlDbType.DateMultirange => "datemultirange",
// Internal types
NpgsqlDbType.Int2Vector => "int2vector",
NpgsqlDbType.Oidvector => "oidvector",
NpgsqlDbType.PgLsn => "pg_lsn",
NpgsqlDbType.Tid => "tid",
NpgsqlDbType.InternalChar => "char",
// Plugin types
NpgsqlDbType.Citext => "citext",
NpgsqlDbType.Cube => "cube",
NpgsqlDbType.LQuery => "lquery",
NpgsqlDbType.LTree => "ltree",
NpgsqlDbType.LTxtQuery => "ltxtquery",
NpgsqlDbType.Hstore => "hstore",
NpgsqlDbType.Geometry => "geometry",
NpgsqlDbType.Geography => "geography",
NpgsqlDbType.Unknown => "unknown",
// Unknown cannot be composed
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Array) && (npgsqlDbType & ~NpgsqlDbType.Array) == NpgsqlDbType.Unknown
=> "unknown",
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Range) && (npgsqlDbType & ~NpgsqlDbType.Range) == NpgsqlDbType.Unknown
=> "unknown",
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Multirange) && (npgsqlDbType & ~NpgsqlDbType.Multirange) == NpgsqlDbType.Unknown
=> "unknown",
_ => npgsqlDbType.HasFlag(NpgsqlDbType.Array)
? ToUnqualifiedDataTypeName(npgsqlDbType & ~NpgsqlDbType.Array) is { } name ? "_" + name : null
: null // e.g. ranges
};
internal static string ToUnqualifiedDataTypeNameOrThrow(this NpgsqlDbType npgsqlDbType)
=> npgsqlDbType.ToUnqualifiedDataTypeName() ?? throw new ArgumentOutOfRangeException(nameof(npgsqlDbType), npgsqlDbType, "Cannot convert NpgsqlDbType to DataTypeName");
/// Can return null when a plugin type or custom range type is used.
internal static DataTypeName? ToDataTypeName(this NpgsqlDbType npgsqlDbType)
=> npgsqlDbType switch
{
// Numeric types
NpgsqlDbType.Smallint => DataTypeNames.Int2,
NpgsqlDbType.Integer => DataTypeNames.Int4,
NpgsqlDbType.Bigint => DataTypeNames.Int8,
NpgsqlDbType.Real => DataTypeNames.Float4,
NpgsqlDbType.Double => DataTypeNames.Float8,
NpgsqlDbType.Numeric => DataTypeNames.Numeric,
NpgsqlDbType.Money => DataTypeNames.Money,
// Text types
NpgsqlDbType.Text => DataTypeNames.Text,
NpgsqlDbType.Xml => DataTypeNames.Xml,
NpgsqlDbType.Varchar => DataTypeNames.Varchar,
NpgsqlDbType.Char => DataTypeNames.Bpchar,
NpgsqlDbType.Name => DataTypeNames.Name,
NpgsqlDbType.Refcursor => DataTypeNames.RefCursor,
NpgsqlDbType.Jsonb => DataTypeNames.Jsonb,
NpgsqlDbType.Json => DataTypeNames.Json,
NpgsqlDbType.JsonPath => DataTypeNames.Jsonpath,
// Date/time types
NpgsqlDbType.Timestamp => DataTypeNames.Timestamp,
NpgsqlDbType.TimestampTz => DataTypeNames.TimestampTz,
NpgsqlDbType.Date => DataTypeNames.Date,
NpgsqlDbType.Time => DataTypeNames.Time,
NpgsqlDbType.TimeTz => DataTypeNames.TimeTz,
NpgsqlDbType.Interval => DataTypeNames.Interval,
// Network types
NpgsqlDbType.Cidr => DataTypeNames.Cidr,
NpgsqlDbType.Inet => DataTypeNames.Inet,
NpgsqlDbType.MacAddr => DataTypeNames.MacAddr,
NpgsqlDbType.MacAddr8 => DataTypeNames.MacAddr8,
// Full-text search types
NpgsqlDbType.TsQuery => DataTypeNames.TsQuery,
NpgsqlDbType.TsVector => DataTypeNames.TsVector,
// Geometry types
NpgsqlDbType.Box => DataTypeNames.Box,
NpgsqlDbType.Circle => DataTypeNames.Circle,
NpgsqlDbType.Line => DataTypeNames.Line,
NpgsqlDbType.LSeg => DataTypeNames.LSeg,
NpgsqlDbType.Path => DataTypeNames.Path,
NpgsqlDbType.Point => DataTypeNames.Point,
NpgsqlDbType.Polygon => DataTypeNames.Polygon,
// UInt types
NpgsqlDbType.Oid => DataTypeNames.Oid,
NpgsqlDbType.Xid => DataTypeNames.Xid,
NpgsqlDbType.Xid8 => DataTypeNames.Xid8,
NpgsqlDbType.Cid => DataTypeNames.Cid,
NpgsqlDbType.Regtype => DataTypeNames.RegType,
NpgsqlDbType.Regconfig => DataTypeNames.RegConfig,
// Misc types
NpgsqlDbType.Boolean => DataTypeNames.Bool,
NpgsqlDbType.Bytea => DataTypeNames.Bytea,
NpgsqlDbType.Uuid => DataTypeNames.Uuid,
NpgsqlDbType.Varbit => DataTypeNames.Varbit,
NpgsqlDbType.Bit => DataTypeNames.Bit,
// Built-in range types
NpgsqlDbType.IntegerRange => DataTypeNames.Int4Range,
NpgsqlDbType.BigIntRange => DataTypeNames.Int8Range,
NpgsqlDbType.NumericRange => DataTypeNames.NumRange,
NpgsqlDbType.TimestampRange => DataTypeNames.TsRange,
NpgsqlDbType.TimestampTzRange => DataTypeNames.TsTzRange,
NpgsqlDbType.DateRange => DataTypeNames.DateRange,
// Internal types
NpgsqlDbType.Int2Vector => DataTypeNames.Int2Vector,
NpgsqlDbType.Oidvector => DataTypeNames.OidVector,
NpgsqlDbType.PgLsn => DataTypeNames.PgLsn,
NpgsqlDbType.Tid => DataTypeNames.Tid,
NpgsqlDbType.InternalChar => DataTypeNames.Char,
// Special types
NpgsqlDbType.Unknown => DataTypeNames.Unknown,
// Unknown cannot be composed
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Array) && (npgsqlDbType & ~NpgsqlDbType.Array) == NpgsqlDbType.Unknown
=> DataTypeNames.Unknown,
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Range) && (npgsqlDbType & ~NpgsqlDbType.Range) == NpgsqlDbType.Unknown
=> DataTypeNames.Unknown,
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Multirange) && (npgsqlDbType & ~NpgsqlDbType.Multirange) == NpgsqlDbType.Unknown
=> DataTypeNames.Unknown,
// If both multirange and array are set we first remove array, so array is added to the outermost datatypename.
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Array)
=> ToDataTypeName(npgsqlDbType & ~NpgsqlDbType.Array)?.ToArrayName(),
_ when npgsqlDbType.HasFlag(NpgsqlDbType.Multirange)
=> ToDataTypeName((npgsqlDbType | NpgsqlDbType.Range) & ~NpgsqlDbType.Multirange)?.ToDefaultMultirangeName(),
// Plugin types don't have a stable fully qualified name.
_ => null
};
internal static NpgsqlDbType? ToNpgsqlDbType(this DataTypeName dataTypeName) => ToNpgsqlDbType(dataTypeName.UnqualifiedName);
/// Should not be used with display names, first normalize it instead.
internal static NpgsqlDbType? ToNpgsqlDbType(string normalizedDataTypeName)
{
var unqualifiedName = normalizedDataTypeName.AsSpan();
if (unqualifiedName.IndexOf('.') is not -1 and var index)
unqualifiedName = unqualifiedName.Slice(index + 1);
return unqualifiedName switch
{
// Numeric types
"int2" => NpgsqlDbType.Smallint,
"int4" => NpgsqlDbType.Integer,
"int8" => NpgsqlDbType.Bigint,
"float4" => NpgsqlDbType.Real,
"float8" => NpgsqlDbType.Double,
"numeric" => NpgsqlDbType.Numeric,
"money" => NpgsqlDbType.Money,
// Text types
"text" => NpgsqlDbType.Text,
"xml" => NpgsqlDbType.Xml,
"varchar" => NpgsqlDbType.Varchar,
"bpchar" => NpgsqlDbType.Char,
"name" => NpgsqlDbType.Name,
"refcursor" => NpgsqlDbType.Refcursor,
"jsonb" => NpgsqlDbType.Jsonb,
"json" => NpgsqlDbType.Json,
"jsonpath" => NpgsqlDbType.JsonPath,
// Date/time types
"timestamp" => NpgsqlDbType.Timestamp,
"timestamptz" => NpgsqlDbType.TimestampTz,
"date" => NpgsqlDbType.Date,
"time" => NpgsqlDbType.Time,
"timetz" => NpgsqlDbType.TimeTz,
"interval" => NpgsqlDbType.Interval,
// Network types
"cidr" => NpgsqlDbType.Cidr,
"inet" => NpgsqlDbType.Inet,
"macaddr" => NpgsqlDbType.MacAddr,
"macaddr8" => NpgsqlDbType.MacAddr8,
// Full-text search types
"tsquery" => NpgsqlDbType.TsQuery,
"tsvector" => NpgsqlDbType.TsVector,
// Geometry types
"box" => NpgsqlDbType.Box,
"circle" => NpgsqlDbType.Circle,
"line" => NpgsqlDbType.Line,
"lseg" => NpgsqlDbType.LSeg,
"path" => NpgsqlDbType.Path,
"point" => NpgsqlDbType.Point,
"polygon" => NpgsqlDbType.Polygon,
// UInt types
"oid" => NpgsqlDbType.Oid,
"xid" => NpgsqlDbType.Xid,
"xid8" => NpgsqlDbType.Xid8,
"cid" => NpgsqlDbType.Cid,
"regtype" => NpgsqlDbType.Regtype,
"regconfig" => NpgsqlDbType.Regconfig,
// Misc types
"bool" => NpgsqlDbType.Boolean,
"bytea" => NpgsqlDbType.Bytea,
"uuid" => NpgsqlDbType.Uuid,
"varbit" => NpgsqlDbType.Varbit,
"bit" => NpgsqlDbType.Bit,
// Built-in range types
"int4range" => NpgsqlDbType.IntegerRange,
"int8range" => NpgsqlDbType.BigIntRange,
"numrange" => NpgsqlDbType.NumericRange,
"tsrange" => NpgsqlDbType.TimestampRange,
"tstzrange" => NpgsqlDbType.TimestampTzRange,
"daterange" => NpgsqlDbType.DateRange,
// Built-in multirange types
"int4multirange" => NpgsqlDbType.IntegerMultirange,
"int8multirange" => NpgsqlDbType.BigIntMultirange,
"nummultirange" => NpgsqlDbType.NumericMultirange,
"tsmultirange" => NpgsqlDbType.TimestampMultirange,
"tstzmultirange" => NpgsqlDbType.TimestampTzMultirange,
"datemultirange" => NpgsqlDbType.DateMultirange,
// Internal types
"int2vector" => NpgsqlDbType.Int2Vector,
"oidvector" => NpgsqlDbType.Oidvector,
"pg_lsn" => NpgsqlDbType.PgLsn,
"tid" => NpgsqlDbType.Tid,
"char" => NpgsqlDbType.InternalChar,
// Plugin types
"citext" => NpgsqlDbType.Citext,
"cube" => NpgsqlDbType.Cube,
"lquery" => NpgsqlDbType.LQuery,
"ltree" => NpgsqlDbType.LTree,
"ltxtquery" => NpgsqlDbType.LTxtQuery,
"hstore" => NpgsqlDbType.Hstore,
"geometry" => NpgsqlDbType.Geometry,
"geography" => NpgsqlDbType.Geography,
_ when unqualifiedName.IndexOf("unknown") != -1
=> !unqualifiedName.StartsWith("_", StringComparison.Ordinal)
? NpgsqlDbType.Unknown
: null,
_ when unqualifiedName.StartsWith("_", StringComparison.Ordinal)
=> ToNpgsqlDbType(unqualifiedName.Slice(1).ToString()) is { } elementNpgsqlDbType
? elementNpgsqlDbType | NpgsqlDbType.Array
: null,
// e.g. custom ranges, plugin types etc.
_ => null
};
}
}