use super::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Maturity {
Experimental,
Preview,
Stable,
Deprecated,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Conformance {
Core,
Optional,
Extension,
}
impl Conformance {
pub const fn is_core(&self) -> bool {
matches!(self, Self::Core)
}
pub const fn is_extension(&self) -> bool {
matches!(self, Self::Extension)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FeatureMetadata {
pub feature: Feature,
pub id: &'static str,
pub iso_id: Option<&'static str>,
pub ideally_enabled: bool,
pub maturity: Maturity,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StandardFeature {
pub id: &'static str,
pub name: &'static str,
pub parent: Option<&'static str>,
pub conformance: Conformance,
pub standardized_in: Option<StandardVersion>,
pub supported: bool,
pub realized_by: Option<Feature>,
}
impl StandardFeature {
pub const fn is_core(&self) -> bool {
self.conformance.is_core()
}
pub const fn is_extension(&self) -> bool {
self.conformance.is_extension()
}
}
pub const STANDARD_FEATURE_CATALOG: &[StandardFeature] = &[
StandardFeature {
id: "E031-01",
name: "Delimited identifiers",
parent: Some("E031"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: Some(Feature::IdentifierQuote),
},
StandardFeature {
id: "E021-07",
name: "Character concatenation",
parent: Some("E021"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: Some(Feature::PipeOperator),
},
StandardFeature {
id: "E021-08",
name: "LIKE predicate",
parent: Some("E021"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: Some(Feature::PredicateSyntax),
},
StandardFeature {
id: "E021-06",
name: "SUBSTRING function",
parent: Some("E021"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "E021-09",
name: "TRIM function",
parent: Some("E021"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "E021-11",
name: "POSITION expression",
parent: Some("E021"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T312",
name: "OVERLAY function",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T611",
name: "Elementary OLAP operations (window functions)",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql2003),
supported: true,
realized_by: None,
},
StandardFeature {
id: "E101",
name: "Basic data manipulation",
parent: None,
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F031",
name: "Basic schema manipulation",
parent: None,
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F031-01",
name: "CREATE TABLE statement",
parent: Some("F031"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F031-02",
name: "CREATE VIEW statement",
parent: Some("F031"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F031-03",
name: "GRANT statement",
parent: Some("F031"),
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F571",
name: "Truth value tests",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T321-01",
name: "User-defined functions with no overloading",
parent: Some("T321"),
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T321-02",
name: "User-defined stored procedures with no overloading",
parent: Some("T321"),
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T321-04",
name: "CALL statement",
parent: Some("T321"),
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T331",
name: "Basic roles",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "T211",
name: "Basic trigger capability",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F034",
name: "Extended REVOKE statement",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: true,
realized_by: None,
},
StandardFeature {
id: "pg:escape-string-syntax",
name: "PostgreSQL E'...' escape string constants",
parent: None,
conformance: Conformance::Extension,
standardized_in: None,
supported: true,
realized_by: Some(Feature::StringLiterals),
},
StandardFeature {
id: "pg:dollar-quoted-strings",
name: "PostgreSQL $tag$...$tag$ string constants",
parent: None,
conformance: Conformance::Extension,
standardized_in: None,
supported: true,
realized_by: Some(Feature::StringLiterals),
},
StandardFeature {
id: "E121",
name: "Basic cursor support",
parent: None,
conformance: Conformance::Core,
standardized_in: Some(StandardVersion::Sql1999),
supported: false,
realized_by: None,
},
StandardFeature {
id: "T176",
name: "Sequence generator support",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql2003),
supported: true,
realized_by: None,
},
StandardFeature {
id: "F251",
name: "Domain support",
parent: None,
conformance: Conformance::Optional,
standardized_in: Some(StandardVersion::Sql1999),
supported: false,
realized_by: None,
},
];
pub fn unsupported_standard_features() -> impl Iterator<Item = &'static StandardFeature> {
STANDARD_FEATURE_CATALOG
.iter()
.filter(|feature| !feature.supported)
}
pub fn standard_feature(id: &str) -> Option<&'static StandardFeature> {
STANDARD_FEATURE_CATALOG
.iter()
.find(|feature| feature.id == id)
}
pub fn standard_features_as_of(
version: StandardVersion,
) -> impl Iterator<Item = &'static StandardFeature> {
STANDARD_FEATURE_CATALOG.iter().filter(
move |feature| matches!(feature.standardized_in, Some(edition) if edition <= version),
)
}
pub fn max_feature_metadata() -> impl Iterator<Item = &'static FeatureMetadata> {
FEATURE_METADATA
.iter()
.filter(|metadata| metadata.ideally_enabled)
}
#[cfg(test)]
mod tests {
use crate::dialect::*;
#[test]
fn feature_metadata_is_enumerable_with_stable_ids() {
assert!(!FEATURES.is_empty());
assert_eq!(FEATURES.len(), FEATURE_METADATA.len());
for (feature, metadata) in FEATURES.iter().zip(FEATURE_METADATA) {
assert_eq!(*feature, metadata.feature);
assert_eq!(feature.id(), metadata.id);
assert!(!metadata.id.is_empty());
assert_eq!(metadata.iso_id, feature.iso_id());
assert_eq!(metadata.ideally_enabled, feature.ideally_enabled());
assert_eq!(metadata.maturity, Maturity::Stable);
}
}
#[test]
fn iso_anchored_features_resolve_in_the_standard_catalog() {
for feature in FEATURES {
let Some(iso_id) = feature.iso_id() else {
continue;
};
let row = standard_feature(iso_id)
.unwrap_or_else(|| panic!("`{iso_id}` missing from STANDARD_FEATURE_CATALOG"));
assert!(
row.supported,
"{iso_id} anchors a knob but is marked unsupported"
);
assert_eq!(row.realized_by, Some(*feature));
assert!(
!row.is_extension(),
"{iso_id} should be a standard id, not an extension"
);
}
}
#[test]
fn realized_standard_features_link_back_to_their_knob() {
for row in STANDARD_FEATURE_CATALOG {
let Some(feature) = row.realized_by else {
continue;
};
assert!(
row.supported,
"{} is realized by a knob but unsupported",
row.id
);
assert!(
FEATURES.contains(&feature),
"{} realized by an unenumerated knob",
row.id
);
if !row.is_extension() {
assert_eq!(feature.iso_id(), Some(row.id));
}
}
}
#[test]
fn standard_catalog_enumerates_unimplemented_negative_space() {
let unsupported: Vec<_> = unsupported_standard_features().collect();
assert!(
!unsupported.is_empty(),
"the registry must enumerate unbuilt standard surface, not only what we added",
);
assert!(
unsupported.iter().any(|feature| feature.is_core()),
"negative space should include at least one mandatory Core feature",
);
let cursors = standard_feature("E121").expect("E121 catalogued");
assert!(!cursors.supported);
assert!(cursors.is_core());
}
#[test]
fn standard_catalog_ids_are_unique_and_well_formed() {
for (index, row) in STANDARD_FEATURE_CATALOG.iter().enumerate() {
assert!(!row.id.is_empty() && !row.name.is_empty());
assert!(
STANDARD_FEATURE_CATALOG[index + 1..]
.iter()
.all(|later| later.id != row.id),
"duplicate standard feature id `{}`",
row.id,
);
if let Some(parent) = row.parent {
assert!(
row.id.starts_with(parent) && row.id.len() > parent.len(),
"`{}` should be a sub-feature of `{parent}`",
row.id,
);
}
assert_eq!(
row.is_extension(),
row.id.contains(':'),
"namespacing must match conformance class for `{}`",
row.id,
);
}
}
#[test]
fn conformance_and_maturity_are_independent_axes() {
let delimited = standard_feature("E031-01").expect("E031-01 catalogued");
assert_eq!(delimited.conformance, Conformance::Core);
assert_eq!(
delimited.realized_by.map(|feature| feature.maturity()),
Some(Maturity::Stable),
);
assert!(Conformance::Core.is_core());
assert!(!Conformance::Core.is_extension());
assert!(Conformance::Extension.is_extension());
}
#[test]
fn standard_features_as_of_grows_monotonically_with_edition() {
let at_1999 = standard_features_as_of(StandardVersion::Sql1999).count();
let at_2003 = standard_features_as_of(StandardVersion::Sql2003).count();
let at_2016 = standard_features_as_of(StandardVersion::Sql2016).count();
assert!(at_1999 >= 1, "SQL:1999 Core features are catalogued");
assert!(
at_2003 > at_1999,
"a SQL:2003 feature (T611) becomes available at the 2003 edition",
);
assert_eq!(
at_2003, at_2016,
"no later-edition feature is catalogued yet"
);
assert!(
standard_feature("T611").unwrap().standardized_in == Some(StandardVersion::Sql2003)
);
assert!(standard_features_as_of(StandardVersion::Sql1999).all(|f| f.id != "T611"));
assert!(standard_features_as_of(StandardVersion::Sql2003).any(|f| f.id == "T611"));
for row in STANDARD_FEATURE_CATALOG {
assert_eq!(
row.standardized_in.is_some(),
!row.is_extension(),
"`{}` edition presence must match standard-vs-extension",
row.id,
);
}
}
#[test]
fn ideally_enabled_excludes_negative_polarity_from_the_max_preset() {
assert_eq!(max_feature_metadata().count(), FEATURE_METADATA.len());
for metadata in FEATURE_METADATA {
assert!(
metadata.ideally_enabled,
"{} should be ideally enabled",
metadata.id
);
}
let restrictive = FeatureMetadata {
feature: Feature::BindingPowers,
id: "strict_example",
iso_id: None,
ideally_enabled: false,
maturity: Maturity::Stable,
};
assert!(!restrictive.ideally_enabled);
assert_eq!(restrictive.maturity, Maturity::Stable);
}
}