Skip to content

Commit b2bdb35

Browse files
Added support for CREATE TYPE
1 parent 308a723 commit b2bdb35

File tree

5 files changed

+726
-45
lines changed

5 files changed

+726
-45
lines changed

src/ast/ddl.rs

Lines changed: 296 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,22 +2002,47 @@ impl fmt::Display for DropBehavior {
20022002
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20032003
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
20042004
pub enum UserDefinedTypeRepresentation {
2005+
/// Composite type: `CREATE TYPE name AS (attributes)`
20052006
Composite {
20062007
attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
20072008
},
2009+
/// Enum type: `CREATE TYPE name AS ENUM (labels)`
2010+
///
20082011
/// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2009-
Enum { labels: Vec<Ident> },
2012+
Enum {
2013+
labels: Vec<Ident>
2014+
},
2015+
/// Range type: `CREATE TYPE name AS RANGE (options)`
2016+
Range {
2017+
options: Vec<UserDefinedTypeRangeOption>,
2018+
},
2019+
/// Base type (SQL definition): `CREATE TYPE name (options)`
2020+
///
2021+
/// Note the lack of `AS` keyword
2022+
SqlDefinition {
2023+
options: Vec<UserDefinedTypeSqlDefinitionOption>,
2024+
},
2025+
/// When the representation of the type is not specified.
2026+
/// This is used in `CREATE TYPE <name>;` statements.
2027+
None,
20102028
}
20112029

20122030
impl fmt::Display for UserDefinedTypeRepresentation {
20132031
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20142032
match self {
2015-
UserDefinedTypeRepresentation::Composite { attributes } => {
2016-
write!(f, "({})", display_comma_separated(attributes))
2033+
Self::Composite { attributes } => {
2034+
write!(f, "AS ({})", display_comma_separated(attributes))
2035+
}
2036+
Self::Enum { labels } => {
2037+
write!(f, "AS ENUM ({})", display_comma_separated(labels))
2038+
}
2039+
Self::Range { options } => {
2040+
write!(f, "AS RANGE ({})", display_comma_separated(options))
20172041
}
2018-
UserDefinedTypeRepresentation::Enum { labels } => {
2019-
write!(f, "ENUM ({})", display_comma_separated(labels))
2042+
Self::SqlDefinition { options } => {
2043+
write!(f, "({})", display_comma_separated(options))
20202044
}
2045+
Self::None => Ok(()),
20212046
}
20222047
}
20232048
}
@@ -2042,6 +2067,272 @@ impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
20422067
}
20432068
}
20442069

2070+
/// Internal length specification for PostgreSQL user-defined base types.
2071+
///
2072+
/// Specifies the internal length in bytes of the new type's internal representation.
2073+
/// The default assumption is that it is variable-length.
2074+
///
2075+
/// # PostgreSQL Documentation
2076+
/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2077+
///
2078+
/// # Examples
2079+
/// ```sql
2080+
/// CREATE TYPE mytype (
2081+
/// INPUT = in_func,
2082+
/// OUTPUT = out_func,
2083+
/// INTERNALLENGTH = 16 -- Fixed 16-byte length
2084+
/// );
2085+
///
2086+
/// CREATE TYPE mytype2 (
2087+
/// INPUT = in_func,
2088+
/// OUTPUT = out_func,
2089+
/// INTERNALLENGTH = VARIABLE -- Variable length
2090+
/// );
2091+
/// ```
2092+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2093+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2094+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2095+
pub enum UserDefinedTypeInternalLength {
2096+
/// Fixed internal length: `INTERNALLENGTH = <number>`
2097+
Fixed(u64),
2098+
/// Variable internal length: `INTERNALLENGTH = VARIABLE`
2099+
Variable,
2100+
}
2101+
2102+
impl fmt::Display for UserDefinedTypeInternalLength {
2103+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2104+
match self {
2105+
UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2106+
UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2107+
}
2108+
}
2109+
}
2110+
2111+
/// Alignment specification for PostgreSQL user-defined base types.
2112+
///
2113+
/// Specifies the storage alignment requirement for values of the data type.
2114+
/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2115+
/// Note that variable-length types must have an alignment of at least 4, since
2116+
/// they necessarily contain an int4 as their first component.
2117+
///
2118+
/// # PostgreSQL Documentation
2119+
/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2120+
///
2121+
/// # Examples
2122+
/// ```sql
2123+
/// CREATE TYPE mytype (
2124+
/// INPUT = in_func,
2125+
/// OUTPUT = out_func,
2126+
/// ALIGNMENT = int4 -- 4-byte alignment
2127+
/// );
2128+
/// ```
2129+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2130+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2131+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2132+
pub enum Alignment {
2133+
/// Single-byte alignment: `ALIGNMENT = char`
2134+
Char,
2135+
/// 2-byte alignment: `ALIGNMENT = int2`
2136+
Int2,
2137+
/// 4-byte alignment: `ALIGNMENT = int4`
2138+
Int4,
2139+
/// 8-byte alignment: `ALIGNMENT = double`
2140+
Double,
2141+
}
2142+
2143+
impl fmt::Display for Alignment {
2144+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2145+
match self {
2146+
Alignment::Char => write!(f, "char"),
2147+
Alignment::Int2 => write!(f, "int2"),
2148+
Alignment::Int4 => write!(f, "int4"),
2149+
Alignment::Double => write!(f, "double"),
2150+
}
2151+
}
2152+
}
2153+
2154+
/// Storage specification for PostgreSQL user-defined base types.
2155+
///
2156+
/// Specifies the storage strategy for values of the data type:
2157+
/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2158+
/// - `external`: Allows out-of-line storage but not compression
2159+
/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2160+
/// - `main`: Allows compression but discourages out-of-line storage
2161+
///
2162+
/// # PostgreSQL Documentation
2163+
/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2164+
///
2165+
/// # Examples
2166+
/// ```sql
2167+
/// CREATE TYPE mytype (
2168+
/// INPUT = in_func,
2169+
/// OUTPUT = out_func,
2170+
/// STORAGE = plain
2171+
/// );
2172+
/// ```
2173+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2174+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2175+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2176+
pub enum UserDefinedTypeStorage {
2177+
/// No compression or out-of-line storage: `STORAGE = plain`
2178+
Plain,
2179+
/// Out-of-line storage allowed, no compression: `STORAGE = external`
2180+
External,
2181+
/// Both compression and out-of-line storage allowed: `STORAGE = extended`
2182+
Extended,
2183+
/// Compression allowed, out-of-line discouraged: `STORAGE = main`
2184+
Main,
2185+
}
2186+
2187+
impl fmt::Display for UserDefinedTypeStorage {
2188+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2189+
match self {
2190+
UserDefinedTypeStorage::Plain => write!(f, "plain"),
2191+
UserDefinedTypeStorage::External => write!(f, "external"),
2192+
UserDefinedTypeStorage::Extended => write!(f, "extended"),
2193+
UserDefinedTypeStorage::Main => write!(f, "main"),
2194+
}
2195+
}
2196+
}
2197+
2198+
/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2199+
///
2200+
/// Range types are data types representing a range of values of some element type
2201+
/// (called the range's subtype). These options configure the behavior of the range type.
2202+
///
2203+
/// # PostgreSQL Documentation
2204+
/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2205+
///
2206+
/// # Examples
2207+
/// ```sql
2208+
/// CREATE TYPE int4range AS RANGE (
2209+
/// SUBTYPE = int4,
2210+
/// SUBTYPE_OPCLASS = int4_ops,
2211+
/// CANONICAL = int4range_canonical,
2212+
/// SUBTYPE_DIFF = int4range_subdiff
2213+
/// );
2214+
/// ```
2215+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2216+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2217+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2218+
pub enum UserDefinedTypeRangeOption {
2219+
/// The element type that the range type will represent: `SUBTYPE = subtype`
2220+
Subtype(DataType),
2221+
/// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2222+
SubtypeOpClass(ObjectName),
2223+
/// Collation to use for ordering the subtype: `COLLATION = collation`
2224+
Collation(ObjectName),
2225+
/// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2226+
Canonical(ObjectName),
2227+
/// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2228+
SubtypeDiff(ObjectName),
2229+
/// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2230+
MultirangeTypeName(ObjectName),
2231+
}
2232+
2233+
impl fmt::Display for UserDefinedTypeRangeOption {
2234+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2235+
match self {
2236+
UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2237+
UserDefinedTypeRangeOption::SubtypeOpClass(name) => write!(f, "SUBTYPE_OPCLASS = {}", name),
2238+
UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2239+
UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2240+
UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2241+
UserDefinedTypeRangeOption::MultirangeTypeName(name) => write!(f, "MULTIRANGE_TYPE_NAME = {}", name),
2242+
}
2243+
}
2244+
}
2245+
2246+
/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2247+
///
2248+
/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2249+
/// you must specify functions that convert it to and from text representation, and optionally
2250+
/// binary representation and other properties.
2251+
///
2252+
/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2253+
///
2254+
/// # PostgreSQL Documentation
2255+
/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2256+
///
2257+
/// # Examples
2258+
/// ```sql
2259+
/// CREATE TYPE complex (
2260+
/// INPUT = complex_in,
2261+
/// OUTPUT = complex_out,
2262+
/// INTERNALLENGTH = 16,
2263+
/// ALIGNMENT = double
2264+
/// );
2265+
/// ```
2266+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2267+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2268+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2269+
pub enum UserDefinedTypeSqlDefinitionOption {
2270+
/// Function to convert from external text representation to internal: `INPUT = input_function`
2271+
Input(ObjectName),
2272+
/// Function to convert from internal to external text representation: `OUTPUT = output_function`
2273+
Output(ObjectName),
2274+
/// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2275+
Receive(ObjectName),
2276+
/// Function to convert from internal to external binary representation: `SEND = send_function`
2277+
Send(ObjectName),
2278+
/// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2279+
TypmodIn(ObjectName),
2280+
/// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2281+
TypmodOut(ObjectName),
2282+
/// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2283+
Analyze(ObjectName),
2284+
/// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2285+
Subscript(ObjectName),
2286+
/// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2287+
InternalLength(UserDefinedTypeInternalLength),
2288+
/// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2289+
PassedByValue,
2290+
/// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2291+
Alignment(Alignment),
2292+
/// Storage strategy for varlena types: `STORAGE = storage`
2293+
Storage(UserDefinedTypeStorage),
2294+
/// Copy properties from an existing type: `LIKE = like_type`
2295+
Like(ObjectName),
2296+
/// Type category for implicit casting rules (single char): `CATEGORY = category`
2297+
Category(char),
2298+
/// Whether this type is preferred within its category: `PREFERRED = preferred`
2299+
Preferred(bool),
2300+
/// Default value for the type: `DEFAULT = default`
2301+
Default(Expr),
2302+
/// Element type for array types: `ELEMENT = element`
2303+
Element(DataType),
2304+
/// Delimiter character for array value display: `DELIMITER = delimiter`
2305+
Delimiter(String),
2306+
/// Whether the type supports collation: `COLLATABLE = collatable`
2307+
Collatable(bool),
2308+
}
2309+
2310+
impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2311+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2312+
match self {
2313+
UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2314+
UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2315+
UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2316+
UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2317+
UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2318+
UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => write!(f, "TYPMOD_OUT = {}", name),
2319+
UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2320+
UserDefinedTypeSqlDefinitionOption::Subscript(name) => write!(f, "SUBSCRIPT = {}", name),
2321+
UserDefinedTypeSqlDefinitionOption::InternalLength(len) => write!(f, "INTERNALLENGTH = {}", len),
2322+
UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2323+
UserDefinedTypeSqlDefinitionOption::Alignment(align) => write!(f, "ALIGNMENT = {}", align),
2324+
UserDefinedTypeSqlDefinitionOption::Storage(storage) => write!(f, "STORAGE = {}", storage),
2325+
UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2326+
UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2327+
UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2328+
UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2329+
UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2330+
UserDefinedTypeSqlDefinitionOption::Delimiter(s) => write!(f, "DELIMITER = '{}'", escape_single_quote_string(s)),
2331+
UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2332+
}
2333+
}
2334+
}
2335+
20452336
/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
20462337
/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
20472338
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)

src/ast/mod.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ pub use self::ddl::{
7171
IdentityPropertyOrder, IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
7272
NullsDistinctOption, Owner, Partition, ProcedureParam, ReferentialAction, RenameTableNameKind,
7373
ReplicaIdentity, TagsColumnOption, TriggerObjectKind, Truncate,
74-
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
74+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeInternalLength, UserDefinedTypeRangeOption,
75+
UserDefinedTypeRepresentation, UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage,
76+
ViewColumnDef, Alignment,
7577
};
7678
pub use self::dml::{Delete, Insert, Update};
7779
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -2787,10 +2789,11 @@ impl fmt::Display for Declare {
27872789
}
27882790

27892791
/// Sql options of a `CREATE TABLE` statement.
2790-
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2792+
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
27912793
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27922794
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
27932795
pub enum CreateTableOptions {
2796+
#[default]
27942797
None,
27952798
/// Options specified using the `WITH` keyword.
27962799
/// e.g. `WITH (description = "123")`
@@ -2819,12 +2822,6 @@ pub enum CreateTableOptions {
28192822
TableProperties(Vec<SqlOption>),
28202823
}
28212824

2822-
impl Default for CreateTableOptions {
2823-
fn default() -> Self {
2824-
Self::None
2825-
}
2826-
}
2827-
28282825
impl fmt::Display for CreateTableOptions {
28292826
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28302827
match self {
@@ -5644,7 +5641,11 @@ impl fmt::Display for Statement {
56445641
name,
56455642
representation,
56465643
} => {
5647-
write!(f, "CREATE TYPE {name} AS {representation}")
5644+
write!(f, "CREATE TYPE {name}")?;
5645+
match representation {
5646+
UserDefinedTypeRepresentation::None => Ok(()),
5647+
repr => write!(f, " {repr}"),
5648+
}
56485649
}
56495650
Statement::Pragma { name, value, is_eq } => {
56505651
write!(f, "PRAGMA {name}")?;

0 commit comments

Comments
 (0)