1use crate::catalog::collations::derivation::Derivation;
10use crate::{ColumnType, SQLError};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
14pub struct ResultCollation {
15 derivation: Derivation,
16 initial_oid: u32,
17}
18
19impl<'de> serde::Deserialize<'de> for ResultCollation {
20 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
21 #[derive(serde::Deserialize)]
22 struct Stored {
23 derivation: Derivation,
24 initial_oid: u32,
25 }
26 let Stored {
27 derivation,
28 initial_oid,
29 } = <Stored as serde::Deserialize>::deserialize(deserializer)?;
30 let valid_oid = |oid| u32::try_from(oid).is_ok();
31 let valid = match derivation {
32 Derivation::None => true,
33 Derivation::Implicit(oid) | Derivation::Explicit(oid) => valid_oid(oid),
34 Derivation::Conflict(left, right) => valid_oid(left) && valid_oid(right),
35 Derivation::InvalidExplicit(..) | Derivation::InvalidImplicit(..) => false,
36 };
37 if !valid {
38 return Err(serde::de::Error::custom(
39 "invalid retained collation selection",
40 ));
41 }
42 Ok(Self::new(derivation, initial_oid))
43 }
44}
45
46impl ResultCollation {
47 pub(crate) fn new(derivation: Derivation, initial_oid: u32) -> Self {
48 Self {
49 derivation,
50 initial_oid,
51 }
52 }
53
54 pub(crate) fn derivation(self) -> Derivation {
55 self.derivation
56 }
57
58 pub(crate) fn initial_oid(self) -> u32 {
59 self.initial_oid
60 }
61
62 pub fn oid(self) -> u32 {
63 u32::try_from(self.derivation.oid()).expect("analyzed result collation OID")
64 }
65
66 pub fn implicit_oid(self) -> Option<u32> {
68 match self.derivation {
69 Derivation::Implicit(_) if self.initial_oid == self.oid() => Some(self.oid()),
70 _ => None,
71 }
72 }
73
74 pub(crate) fn validate(self, ty: &ColumnType) -> Result<(), SQLError> {
75 self.derivation.validate()?;
76 crate::catalog::collations::expression::validate_literal_collation(
77 Some(ty),
78 Some(self.oid()),
79 )
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn result_collation_codec_preserves_coercibility_and_rejects_invalid_identities() {
89 for derivation in [
90 Derivation::None,
91 Derivation::Implicit(950),
92 Derivation::Explicit(100),
93 Derivation::Conflict(950, 951),
94 ] {
95 let selection = ResultCollation::new(derivation, 0);
96 let encoded = serde_json::to_string(&selection).unwrap();
97 let restored: ResultCollation = serde_json::from_str(&encoded).unwrap();
98 assert_eq!(restored, selection);
99 assert_eq!(restored.initial_oid(), 0);
100 assert!(restored.implicit_oid().is_none());
101 }
102 assert_eq!(
103 ResultCollation::new(Derivation::Implicit(950), 950).implicit_oid(),
104 Some(950)
105 );
106 for derivation in [
107 Derivation::Implicit(-1),
108 Derivation::Explicit(i64::from(u32::MAX) + 1),
109 Derivation::Conflict(950, -1),
110 Derivation::InvalidExplicit(950, 951),
111 Derivation::InvalidImplicit(950, 951),
112 ] {
113 let invalid = ResultCollation::new(derivation, 0);
114 assert!(serde_json::from_str::<ResultCollation>(
115 &serde_json::to_string(&invalid).unwrap()
116 )
117 .is_err());
118 }
119 }
120}