1use serde::{Deserialize, Serialize};
13
14mod expressions;
15mod locking;
16
17pub use expressions::*;
18pub use locking::*;
19
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub enum ColumnType {
22 SmallInteger,
23 Integer,
24 BigInteger,
25 Oid,
27 Xid,
29 Boolean,
30 Text,
31 Name,
32 Uuid,
33 Varchar(Option<u32>),
34 Bpchar,
36 Character(u32),
40 Real,
41 DoublePrecision,
42 Numeric {
47 precision: Option<u32>,
48 scale: Option<i32>,
49 },
50 Json,
52 JsonB,
54 Bytea,
56 InternalChar,
58 Regproc,
59 Regclass,
61 Regnamespace,
63 Regtype,
64 PgNodeTree,
65 AclItem,
66 Int2Vector,
67 OidVector,
68 AnyArray,
69 Record,
71 Array(Box<ColumnType>),
74 Date,
76 Time,
78 TimeTz,
80 Timestamp,
83 TimestampTz,
86 Interval,
87 Vector(u32),
89 Tensor(u32),
93 Domain {
96 schema: String,
97 name: String,
98 oid: u32,
99 base: Box<ColumnType>,
100 },
101}
102
103pub(crate) fn builtin_array_element_name(type_name: &str) -> Option<&'static str> {
104 Some(match type_name {
105 "_bool" => "bool",
106 "_bytea" => "bytea",
107 "_char" => "\"char\"",
108 "_name" => "name",
109 "_int8" => "int8",
110 "_int2" => "int2",
111 "_int2vector" => "int2vector",
112 "_int4" => "int4",
113 "_regproc" => "regproc",
114 "_regclass" => "regclass",
115 "_text" => "text",
116 "_oid" => "oid",
117 "_oidvector" => "oidvector",
118 "_bpchar" => "bpchar",
119 "_varchar" => "varchar",
120 "_float4" => "float4",
121 "_float8" => "float8",
122 "_aclitem" => "aclitem",
123 "_date" => "date",
124 "_time" => "time",
125 "_timestamp" => "timestamp",
126 "_timestamptz" => "timestamptz",
127 "_interval" => "interval",
128 "_numeric" => "numeric",
129 "_timetz" => "timetz",
130 "_record" => "record",
131 "_uuid" => "uuid",
132 "_json" => "json",
133 "_jsonb" => "jsonb",
134 "_regtype" => "regtype",
135 "_xid" => "xid",
136 "_pg_node_tree" => "pg_node_tree",
137 _ => return None,
138 })
139}
140
141impl ColumnType {
142 #[must_use]
143 pub fn is_integer(&self) -> bool {
144 match self {
145 Self::SmallInteger | Self::Integer | Self::BigInteger | Self::Oid | Self::Xid => true,
146 Self::Domain { base, .. } => base.is_integer(),
147 _ => false,
148 }
149 }
150
151 #[must_use]
152 pub fn is_character_string(&self) -> bool {
153 match self {
154 Self::Text
155 | Self::Name
156 | Self::Varchar(_)
157 | Self::Bpchar
158 | Self::Character(_)
159 | Self::InternalChar
160 | Self::PgNodeTree
161 | Self::AclItem => true,
162 Self::Domain { base, .. } => base.is_character_string(),
163 _ => false,
164 }
165 }
166
167 pub fn from_sql_name(name: &str) -> Result<Self, crate::SQLError> {
171 let normalized = name.trim().to_ascii_lowercase();
172 if let Some(element) = builtin_array_element_name(&normalized) {
173 return Self::from_sql_name(element).map(|ty| Self::Array(Box::new(ty)));
174 }
175 if let Some(element) = normalized.strip_suffix("[]") {
176 return Self::from_sql_name(element).map(|ty| Self::Array(Box::new(ty)));
177 }
178 let (base, modifier) = normalized
179 .strip_suffix(')')
180 .and_then(|prefix| prefix.rsplit_once('('))
181 .map_or((normalized.as_str(), None), |(base, modifier)| {
182 (base.trim(), Some(modifier.trim()))
183 });
184 let base = base.strip_prefix("pg_catalog.").unwrap_or(base);
185 let character_length = || -> Result<Option<u32>, crate::SQLError> {
186 modifier
187 .map(|value| {
188 value
189 .parse::<u32>()
190 .ok()
191 .filter(|length| *length > 0)
192 .ok_or_else(|| {
193 crate::SQLError::TypeMismatch(format!(
194 "character length must be greater than zero, got {value}"
195 ))
196 })
197 })
198 .transpose()
199 };
200 match base {
201 "smallint" | "int2" | "smallserial" | "serial2" => Ok(Self::SmallInteger),
202 "integer" | "int" | "int4" | "serial" | "serial4" => Ok(Self::Integer),
203 "bigint" | "int8" | "bigserial" | "serial8" => Ok(Self::BigInteger),
204 "oid" => Ok(Self::Oid),
205 "xid" => Ok(Self::Xid),
206 "boolean" | "bool" => Ok(Self::Boolean),
207 "text" => Ok(Self::Text),
208 "name" => Ok(Self::Name),
209 "uuid" => Ok(Self::Uuid),
210 "varchar" | "character varying" => Ok(Self::Varchar(character_length()?)),
211 "character" | "char" => Ok(Self::Character(character_length()?.unwrap_or(1))),
212 "bpchar" => Ok(character_length()?.map_or(Self::Bpchar, Self::Character)),
213 "real" | "float4" => Ok(Self::Real),
214 "double" | "double precision" | "float8" => Ok(Self::DoublePrecision),
215 "numeric" | "decimal" => {
216 let (precision, scale) = match modifier {
217 None => (None, None),
218 Some(modifier) => {
219 let mut parts = modifier.split(',').map(str::trim);
220 let precision = parts
221 .next()
222 .and_then(|value| value.parse::<u32>().ok())
223 .ok_or_else(|| {
224 crate::SQLError::TypeMismatch(format!(
225 "invalid numeric modifier `{modifier}`"
226 ))
227 })?;
228 let scale = parts
229 .next()
230 .map(|value| value.parse::<i32>())
231 .transpose()
232 .map_err(|_| {
233 crate::SQLError::TypeMismatch(format!(
234 "invalid numeric modifier `{modifier}`"
235 ))
236 })?
237 .unwrap_or(0);
238 if parts.next().is_some() {
239 return Err(crate::SQLError::TypeMismatch(format!(
240 "invalid numeric modifier `{modifier}`"
241 )));
242 }
243 (Some(precision), Some(scale))
244 }
245 };
246 Ok(Self::Numeric { precision, scale })
247 }
248 "json" => Ok(Self::Json),
249 "jsonb" => Ok(Self::JsonB),
250 "bytea" => Ok(Self::Bytea),
251 "\"char\"" => Ok(Self::InternalChar),
252 "regproc" => Ok(Self::Regproc),
253 "regclass" => Ok(Self::Regclass),
254 "regnamespace" => Ok(Self::Regnamespace),
255 "regtype" => Ok(Self::Regtype),
256 "pg_node_tree" => Ok(Self::PgNodeTree),
257 "aclitem" => Ok(Self::AclItem),
258 "int2vector" => Ok(Self::Int2Vector),
259 "oidvector" => Ok(Self::OidVector),
260 "anyarray" => Ok(Self::AnyArray),
261 "record" => Ok(Self::Record),
262 "date" => Ok(Self::Date),
263 "time" | "time without time zone" => Ok(Self::Time),
264 "timetz" | "time with time zone" => Ok(Self::TimeTz),
265 "timestamp" | "datetime" | "timestamp without time zone" => Ok(Self::Timestamp),
266 "timestamptz" | "timestamp with time zone" => Ok(Self::TimestampTz),
267 "interval" => Ok(Self::Interval),
268 "vector" => modifier
269 .and_then(|value| value.parse::<u32>().ok())
270 .filter(|dimension| *dimension > 0)
271 .map(Self::Vector)
272 .ok_or_else(|| crate::SQLError::TypeMismatch("VECTOR requires a dimension".into())),
273 "tensor" => modifier
274 .and_then(|value| value.parse::<u32>().ok())
275 .filter(|dimension| *dimension > 0)
276 .map(Self::Tensor)
277 .ok_or_else(|| crate::SQLError::TypeMismatch("TENSOR requires a dimension".into())),
278 other => Err(crate::SQLError::Unsupported(format!(
279 "SQL type `{other}` is not supported"
280 ))),
281 }
282 }
283
284 #[must_use]
285 pub fn sql_name(&self) -> String {
286 match self {
287 Self::SmallInteger => "smallint".into(),
288 Self::Integer => "integer".into(),
289 Self::BigInteger => "bigint".into(),
290 Self::Oid => "oid".into(),
291 Self::Xid => "xid".into(),
292 Self::Boolean => "boolean".into(),
293 Self::Text => "text".into(),
294 Self::Name => "name".into(),
295 Self::Uuid => "uuid".into(),
296 Self::Varchar(Some(length)) => format!("character varying({length})"),
297 Self::Varchar(None) => "character varying".into(),
298 Self::Bpchar => "bpchar".into(),
299 Self::Character(length) => format!("character({length})"),
300 Self::Real => "real".into(),
301 Self::DoublePrecision => "double precision".into(),
302 Self::Numeric {
303 precision: Some(precision),
304 scale: Some(scale),
305 } => format!("numeric({precision},{scale})"),
306 Self::Numeric { .. } => "numeric".into(),
307 Self::Json => "json".into(),
308 Self::JsonB => "jsonb".into(),
309 Self::Bytea => "bytea".into(),
310 Self::InternalChar => "\"char\"".into(),
311 Self::Regproc => "regproc".into(),
312 Self::Regclass => "regclass".into(),
313 Self::Regnamespace => "regnamespace".into(),
314 Self::Regtype => "regtype".into(),
315 Self::PgNodeTree => "pg_node_tree".into(),
316 Self::AclItem => "aclitem".into(),
317 Self::Int2Vector => "int2vector".into(),
318 Self::OidVector => "oidvector".into(),
319 Self::AnyArray => "anyarray".into(),
320 Self::Record => "record".into(),
321 Self::Array(element) => format!("{}[]", element.sql_name()),
322 Self::Date => "date".into(),
323 Self::Time => "time without time zone".into(),
324 Self::TimeTz => "time with time zone".into(),
325 Self::Timestamp => "timestamp without time zone".into(),
326 Self::TimestampTz => "timestamp with time zone".into(),
327 Self::Interval => "interval".into(),
328 Self::Vector(dimension) => format!("vector({dimension})"),
329 Self::Tensor(dimension) => format!("tensor({dimension})"),
330 Self::Domain { schema, name, .. } => format!("{schema}.{name}"),
331 }
332 }
333
334 #[must_use]
337 pub fn regtype_name(&self) -> String {
338 match self {
339 Self::Varchar(_) => "character varying".into(),
340 Self::Bpchar | Self::Character(_) => "character".into(),
341 Self::Numeric { .. } => "numeric".into(),
342 Self::Vector(_) => "vector".into(),
343 Self::Tensor(_) => "tensor".into(),
344 Self::Domain { schema, name, .. } => format!("{schema}.{name}"),
345 Self::Array(element) => format!("{}[]", element.regtype_name()),
346 other => other.sql_name(),
347 }
348 }
349}
350
351#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
352pub enum GeneratedColumnKind {
353 Virtual,
354 Stored,
355}
356
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct GeneratedColumn {
359 pub kind: GeneratedColumnKind,
360 pub expression: Box<Expr>,
361 #[serde(default, skip_serializing_if = "Vec::is_empty")]
362 pub function_dependencies: Vec<GeneratedFunctionDependency>,
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
366pub struct FunctionBinding {
367 pub name: String,
368 pub argument_types: Vec<String>,
369}
370
371pub type GeneratedFunctionDependency = FunctionBinding;
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
374#[allow(clippy::struct_excessive_bools)]
375pub struct ColumnDef {
376 pub name: String,
377 pub ty: ColumnType,
378 pub primary_key: bool,
379 pub not_null: bool,
380 #[serde(default)]
383 pub not_null_explicit: bool,
384 #[serde(default, skip_serializing_if = "Option::is_none")]
388 pub not_null_name: Option<String>,
389 #[serde(default)]
392 pub auto_increment: bool,
393 #[serde(default)]
396 pub unique: bool,
397 #[serde(default, skip_serializing_if = "Option::is_none")]
401 pub default: Option<Expr>,
402 #[serde(default, skip_serializing_if = "Option::is_none")]
406 pub generated: Option<GeneratedColumn>,
407 #[serde(default, skip_serializing_if = "Option::is_none")]
410 pub check: Option<Expr>,
411 #[serde(default, skip_serializing_if = "Option::is_none")]
412 pub check_name: Option<String>,
413 #[serde(default = "default_true")]
414 pub check_enforced: bool,
415 #[serde(default, skip_serializing_if = "Option::is_none")]
419 pub references: Option<ForeignKeyRef>,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize)]
424pub struct ForeignKeyRef {
425 #[serde(default, skip_serializing_if = "Option::is_none")]
426 pub name: Option<String>,
427 pub table: String,
428 pub column: String,
429 #[serde(default)]
430 pub on_update: ForeignKeyAction,
431 #[serde(default)]
432 pub on_delete: ForeignKeyAction,
433 #[serde(default)]
434 pub match_type: ForeignKeyMatch,
435 #[serde(default = "default_true")]
436 pub enforced: bool,
437}
438
439#[derive(Debug, Clone, Serialize, Deserialize)]
440pub struct CreateTable {
441 pub name: String,
442 pub qualifier: String,
444 pub columns: Vec<ColumnDef>,
445 pub if_not_exists: bool,
448 #[allow(dead_code)]
451 pub checks: Vec<TableCheck>,
452 pub foreign_keys: Vec<ForeignKey>,
454 #[serde(default)]
459 pub key_constraints: Vec<TableKeyConstraint>,
460}
461
462#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
463pub enum TableKeyConstraintKind {
464 PrimaryKey,
465 Unique,
466}
467
468#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
470pub struct TableKeyConstraint {
471 pub name: Option<String>,
472 pub kind: TableKeyConstraintKind,
473 pub columns: Vec<String>,
474 #[serde(default)]
477 pub nulls_not_distinct: bool,
478}
479
480#[derive(Debug, Clone, Default, Serialize, Deserialize)]
485pub struct TableConstraintSet {
486 #[serde(default)]
487 pub checks: Vec<TableCheck>,
488 #[serde(default)]
489 pub foreign_keys: Vec<ForeignKey>,
490 #[serde(default)]
491 pub key_constraints: Vec<TableKeyConstraint>,
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize)]
497pub struct TableCheck {
498 pub name: Option<String>,
499 pub expr: Expr,
500 #[serde(default = "default_true")]
501 pub enforced: bool,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
508pub struct ForeignKey {
509 pub name: Option<String>,
510 pub local_columns: Vec<String>,
511 pub ref_table: String,
512 pub ref_columns: Vec<String>,
513 #[serde(default)]
514 pub on_update: ForeignKeyAction,
515 #[serde(default)]
516 pub on_delete: ForeignKeyAction,
517 #[serde(default)]
521 pub on_delete_set_columns: Vec<String>,
522 #[serde(default)]
523 pub match_type: ForeignKeyMatch,
524 #[serde(default = "default_true")]
525 pub enforced: bool,
526}
527
528const fn default_true() -> bool {
529 true
530}
531
532#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
533pub enum ForeignKeyAction {
534 #[default]
535 NoAction,
536 Restrict,
537 Cascade,
538 SetNull,
539 SetDefault,
540}
541
542#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
543pub enum ForeignKeyMatch {
544 #[default]
545 Simple,
546 Full,
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize)]
550pub struct CreateIndex {
551 pub name: Option<String>,
552 pub table: String,
553 pub access_method: String,
555 pub columns: Vec<String>,
556 pub if_not_exists: bool,
558 pub options: Vec<(String, String)>,
562}
563
564#[derive(Debug, Clone, Serialize, Deserialize)]
565pub struct DropStmt {
566 pub kind: DropKind,
567 pub names: Vec<String>,
568 pub if_exists: bool,
569 pub cascade: bool,
570}
571
572#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
573pub enum DropKind {
574 Table,
575 Index,
576 View,
577 Schema,
578}
579
580#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
583pub enum FunctionParamMode {
584 In,
586 Out,
589 InOut,
591 Table,
594}
595
596#[derive(Debug, Clone, Serialize, Deserialize)]
598pub struct FunctionParam {
599 pub name: String,
602 pub type_name: String,
605 #[serde(default, skip_serializing_if = "Option::is_none")]
607 pub type_reference: Option<RoutineColumnTypeReference>,
608 pub mode: FunctionParamMode,
609 #[serde(default, skip_serializing_if = "Option::is_none")]
611 pub default: Option<Expr>,
612}
613
614#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
616pub struct RoutineColumnTypeReference {
617 pub schema: Option<String>,
618 pub relation: String,
619 pub column: String,
620}
621
622impl RoutineColumnTypeReference {
623 pub fn new(schema: Option<String>, relation: String, column: String) -> Self {
624 Self {
625 schema,
626 relation,
627 column,
628 }
629 }
630
631 pub fn relation_reference(&self) -> String {
632 match self.schema.as_deref() {
633 Some(schema) => format!(
634 "{}.{}",
635 render_identifier_component(schema),
636 render_identifier_component(&self.relation)
637 ),
638 None => render_identifier_component(&self.relation),
639 }
640 }
641
642 pub fn type_reference(&self) -> String {
643 format!(
644 "{}.{}%type",
645 self.relation_reference(),
646 render_identifier_component(&self.column)
647 )
648 }
649}
650
651fn render_identifier_component(component: &str) -> String {
652 let can_render_bare = component
653 .bytes()
654 .enumerate()
655 .all(|(index, byte)| match byte {
656 b'a'..=b'z' | b'_' => true,
657 b'0'..=b'9' | b'$' => index != 0,
658 _ => false,
659 });
660 if can_render_bare && !component.is_empty() {
661 component.to_string()
662 } else {
663 format!("\"{}\"", component.replace('"', "\"\""))
664 }
665}
666
667#[derive(Debug, Clone, Serialize, Deserialize)]
669pub enum FunctionReturns {
670 None,
673 Scalar { type_name: String },
675 SetOf { type_name: String },
677 Table,
681}
682
683#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
685pub enum FunctionVolatility {
686 Immutable,
687 Stable,
688 #[default]
689 Volatile,
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize)]
694pub enum FunctionBody {
695 Source(String),
698 Statements(Vec<Statement>),
701}
702
703#[derive(Debug, Clone, Serialize, Deserialize)]
705pub struct CreateFunction {
706 pub name: String,
707 pub or_replace: bool,
708 pub is_procedure: bool,
709 pub params: Vec<FunctionParam>,
710 pub returns: FunctionReturns,
711 #[serde(default, skip_serializing_if = "Option::is_none")]
713 pub return_type_reference: Option<RoutineColumnTypeReference>,
714 pub language: String,
716 pub body: FunctionBody,
717 pub volatility: FunctionVolatility,
718 pub strict: bool,
721}
722
723impl CreateFunction {
724 pub fn signature_arity(&self) -> usize {
729 self.params
730 .iter()
731 .filter(|p| self.is_signature_param(p))
732 .count()
733 }
734
735 pub fn required_arity(&self) -> usize {
737 self.params
738 .iter()
739 .filter(|p| self.is_signature_param(p) && p.default.is_none())
740 .count()
741 }
742
743 fn is_signature_param(&self, p: &FunctionParam) -> bool {
744 match p.mode {
745 FunctionParamMode::In | FunctionParamMode::InOut => true,
746 FunctionParamMode::Out => self.is_procedure,
747 FunctionParamMode::Table => false,
748 }
749 }
750
751 pub fn signature_params(&self) -> Vec<&FunctionParam> {
753 self.params
754 .iter()
755 .filter(|p| self.is_signature_param(p))
756 .collect()
757 }
758
759 pub fn output_params(&self) -> Vec<&FunctionParam> {
762 self.params
763 .iter()
764 .filter(|p| {
765 matches!(
766 p.mode,
767 FunctionParamMode::Out | FunctionParamMode::InOut | FunctionParamMode::Table
768 )
769 })
770 .collect()
771 }
772
773 pub fn returns_set(&self) -> bool {
776 matches!(
777 self.returns,
778 FunctionReturns::SetOf { .. } | FunctionReturns::Table
779 )
780 }
781}
782
783#[derive(Debug, Clone, Serialize, Deserialize)]
785pub struct DropFunctionItem {
786 pub name: String,
787 pub arg_types: Option<Vec<String>>,
792}
793
794#[derive(Debug, Clone, Serialize, Deserialize)]
797pub struct DropFunctionStmt {
798 pub is_procedure: bool,
799 pub if_exists: bool,
800 #[serde(default)]
801 pub cascade: bool,
802 pub items: Vec<DropFunctionItem>,
803}
804
805#[derive(Debug, Clone, Serialize, Deserialize)]
806pub struct AlterTableStmt {
807 pub table: String,
808 pub qualifier: String,
810 pub if_exists: bool,
811 pub action: AlterTableAction,
812}
813
814#[derive(Debug, Clone, Serialize, Deserialize)]
815#[allow(clippy::large_enum_variant)]
816pub enum AlterTableAction {
817 AddColumn {
818 column: ColumnDef,
819 if_not_exists: bool,
820 },
821 AddKeyConstraint {
822 constraint: TableKeyConstraint,
823 },
824 DropColumn {
825 name: String,
826 if_exists: bool,
827 cascade: bool,
828 },
829 RenameColumn {
830 from: String,
831 to: String,
832 },
833 RenameTable {
834 to: String,
835 },
836 SetDefault {
837 name: String,
838 default: Expr,
839 },
840 DropDefault {
841 name: String,
842 },
843 SetExpression {
844 name: String,
845 expression: Expr,
846 },
847 DropExpression {
848 name: String,
849 },
850 SetNotNull {
851 name: String,
852 },
853 DropNotNull {
854 name: String,
855 },
856 AlterColumnType {
857 name: String,
858 ty: ColumnType,
859 #[serde(default, skip_serializing_if = "Option::is_none")]
860 using: Option<Expr>,
861 },
862}
863
864#[derive(Debug, Clone, Serialize, Deserialize)]
865pub struct InsertStmt {
866 pub table: String,
867 pub target_qualifier: String,
869 pub columns: Vec<String>,
870 pub with: Vec<CTE>,
872 pub rows: Vec<Vec<ValueExpr>>,
876 pub select_source: Option<Box<SelectStmt>>,
880 pub on_conflict: Option<OnConflict>,
883 pub returning: Vec<Projection>,
885 pub returning_aliases: ReturningAliases,
888}
889
890#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
891pub struct ReturningAliases {
892 pub old: String,
893 pub new: String,
894 #[serde(default)]
895 pub old_explicit: bool,
896 #[serde(default)]
897 pub new_explicit: bool,
898}
899
900impl Default for ReturningAliases {
901 fn default() -> Self {
902 Self {
903 old: "old".into(),
904 new: "new".into(),
905 old_explicit: false,
906 new_explicit: false,
907 }
908 }
909}
910
911#[derive(Debug, Clone, Serialize, Deserialize)]
912pub struct OnConflict {
913 pub conflict_columns: Vec<String>,
917 pub action: OnConflictAction,
918}
919
920#[derive(Debug, Clone, Serialize, Deserialize)]
921pub enum OnConflictAction {
922 Nothing,
924 Update {
928 assignments: Vec<(String, Expr)>,
929 r#where: Option<Expr>,
930 },
931}
932
933#[derive(Debug, Clone, Serialize, Deserialize)]
934pub struct SelectStmt {
935 pub projections: Vec<Projection>,
936 #[serde(default, skip_serializing_if = "Vec::is_empty")]
940 pub values: Vec<Vec<Expr>>,
941 pub from: Option<FromClause>,
942 pub r#where: Option<Expr>,
943 pub group_by: Vec<Expr>,
944 pub grouping_sets: Vec<Vec<Expr>>,
950 pub having: Option<Expr>,
954 pub order_by: Vec<OrderBy>,
955 pub limit: Option<Expr>,
959 pub offset: Option<Expr>,
961 pub with: Vec<CTE>,
963 pub set_op: Option<Box<SetOp>>,
967 pub distinct: bool,
970 pub distinct_on: Vec<Expr>,
973 #[serde(default, skip_serializing_if = "Vec::is_empty")]
975 pub locking: Vec<LockingClause>,
976}
977
978#[derive(Debug, Clone, Serialize, Deserialize)]
979pub struct CTE {
980 pub name: String,
981 pub columns: Vec<String>,
982 pub recursive: bool,
983 pub query: Box<SelectStmt>,
984}
985
986#[derive(Debug, Clone, Serialize, Deserialize)]
987pub struct SetOp {
988 pub kind: SetOpKind,
989 pub all: bool,
990 #[serde(default, skip_serializing_if = "Option::is_none")]
994 pub left: Option<Box<SelectStmt>>,
995 pub right: SelectStmt,
996 pub combined_order_by: Vec<OrderBy>,
999 pub combined_limit: Option<Expr>,
1002 pub combined_offset: Option<Expr>,
1004}
1005
1006#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1007pub enum SetOpKind {
1008 Union,
1009 Intersect,
1010 Except,
1011}
1012
1013#[derive(Debug, Clone, Serialize, Deserialize)]
1014pub enum FromClause {
1015 Table {
1017 name: String,
1019 qualifier: String,
1021 alias: Option<String>,
1022 },
1023 Join {
1027 left: Box<FromClause>,
1028 right: Box<FromClause>,
1029 kind: JoinKind,
1030 on: Option<Expr>,
1033 #[serde(default, skip_serializing_if = "Option::is_none")]
1037 using: Option<JoinUsing>,
1038 #[serde(default)]
1041 natural: bool,
1042 #[allow(dead_code)]
1043 lateral: bool,
1044 },
1045 Values {
1047 rows: Vec<Vec<Expr>>,
1048 alias: Option<String>,
1049 column_aliases: Vec<String>,
1050 },
1051 Function {
1056 name: String,
1057 output_name: String,
1059 #[serde(default, skip_serializing_if = "Option::is_none")]
1063 relation: Option<String>,
1064 args: Vec<Expr>,
1065 alias: Option<String>,
1066 column_aliases: Vec<String>,
1067 #[serde(default)]
1072 column_types: Vec<String>,
1073 },
1074 Subquery {
1078 body: Box<SelectStmt>,
1079 alias: Option<String>,
1080 column_aliases: Vec<String>,
1081 },
1082}
1083
1084#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1085pub struct JoinUsing {
1086 pub columns: Vec<String>,
1087 #[serde(default, skip_serializing_if = "Option::is_none")]
1088 pub alias: Option<String>,
1089}
1090
1091impl FromClause {
1092 pub fn collect_tables(&self, out: &mut Vec<(String, Option<String>)>) {
1095 match self {
1096 FromClause::Table {
1097 name,
1098 qualifier,
1099 alias,
1100 } => out.push((
1101 name.clone(),
1102 Some(alias.as_ref().unwrap_or(qualifier).clone()),
1103 )),
1104 FromClause::Join { left, right, .. } => {
1105 left.collect_tables(out);
1106 right.collect_tables(out);
1107 }
1108 FromClause::Values { alias, .. }
1109 | FromClause::Function { alias, .. }
1110 | FromClause::Subquery { alias, .. } => {
1111 if let Some(a) = alias {
1112 out.push((a.clone(), Some(a.clone())));
1113 }
1114 }
1115 }
1116 }
1117}
1118
1119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1120pub enum JoinKind {
1121 Inner,
1122 Left,
1123 Right,
1124 Full,
1125 Cross,
1126}
1127
1128#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1130pub enum DiscardTarget {
1131 All,
1132 Plans,
1133 Sequences,
1134 Temp,
1135}
1136
1137#[derive(Debug, Clone, Serialize, Deserialize)]
1138pub struct UpdateStmt {
1139 pub table: String,
1140 pub target_qualifier: String,
1141 pub assignments: Vec<(String, Expr)>,
1142 pub r#where: Option<Expr>,
1143 pub with: Vec<CTE>,
1145 pub from: Option<FromClause>,
1148 pub returning: Vec<Projection>,
1150 pub returning_aliases: ReturningAliases,
1151}
1152
1153#[derive(Debug, Clone, Serialize, Deserialize)]
1154pub struct DeleteStmt {
1155 pub table: String,
1156 pub target_qualifier: String,
1157 pub r#where: Option<Expr>,
1158 pub with: Vec<CTE>,
1160 pub using: Option<FromClause>,
1164 pub returning: Vec<Projection>,
1166 pub returning_aliases: ReturningAliases,
1167}
1168
1169#[derive(Debug, Clone, Serialize, Deserialize)]
1170pub enum Statement {
1171 CreateTable(CreateTable),
1172 CreateIndex(CreateIndex),
1173 Insert(InsertStmt),
1174 Select(Box<SelectStmt>),
1178 Update(UpdateStmt),
1179 Delete(DeleteStmt),
1180 Drop(DropStmt),
1181 AlterTable(AlterTableStmt),
1182 CreateView {
1186 name: String,
1187 body: Box<SelectStmt>,
1188 or_replace: bool,
1189 },
1190 CreateSchema {
1194 name: String,
1195 if_not_exists: bool,
1196 },
1197 SetVariable {
1201 name: String,
1202 value: String,
1203 },
1204 ShowVariable {
1207 name: String,
1208 },
1209 Discard {
1214 target: DiscardTarget,
1215 },
1216 Load {
1221 library: String,
1222 },
1223 Explain {
1226 analyze: bool,
1227 verbose: bool,
1228 format: Option<String>,
1229 body: Box<Statement>,
1230 },
1231 Analyze {
1234 table: Option<String>,
1235 },
1236 Truncate {
1238 tables: Vec<String>,
1239 cascade: bool,
1240 },
1241 Transaction(TransactionStmt),
1243 CreateSequence(CreateSequence),
1245 AlterSequence(AlterSequence),
1248 CreateTableAs {
1250 name: String,
1251 if_not_exists: bool,
1252 body: Box<SelectStmt>,
1253 },
1254 Prepare {
1256 name: String,
1257 body: Box<Statement>,
1258 },
1259 Execute {
1261 name: String,
1262 params: Vec<Expr>,
1263 },
1264 Deallocate {
1266 name: Option<String>,
1267 },
1268 Values {
1271 rows: Vec<Vec<Expr>>,
1272 },
1273 CreateForeignServer(CreateForeignServer),
1275 CreateForeignTable(CreateForeignTable),
1277 Merge(MergeStmt),
1280 CreateFunction(Box<CreateFunction>),
1283 DropFunction(DropFunctionStmt),
1285 DoBlock {
1287 language: String,
1288 body: String,
1289 },
1290 Call {
1293 name: String,
1294 args: Vec<Expr>,
1295 },
1296}
1297
1298#[derive(Debug, Clone, Serialize, Deserialize)]
1299pub struct MergeStmt {
1300 pub target: String,
1301 pub target_qualifier: String,
1302 pub target_alias: Option<String>,
1303 pub source: FromClause,
1304 pub join_condition: Expr,
1305 pub when_clauses: Vec<MergeWhen>,
1306 pub returning: Vec<Projection>,
1308 pub returning_aliases: ReturningAliases,
1309}
1310
1311#[derive(Debug, Clone, Serialize, Deserialize)]
1312pub enum MergeWhen {
1313 UpdateMatched {
1315 condition: Option<Expr>,
1316 assignments: Vec<(String, Expr)>,
1317 },
1318 DeleteMatched { condition: Option<Expr> },
1320 InsertNotMatched {
1322 condition: Option<Expr>,
1323 columns: Vec<String>,
1324 values: Vec<Expr>,
1325 },
1326 NothingMatched { condition: Option<Expr> },
1328 NothingNotMatched { condition: Option<Expr> },
1330}
1331
1332#[derive(Debug, Clone, Serialize, Deserialize)]
1333pub struct CreateForeignServer {
1334 pub name: String,
1335 pub fdw_type: String,
1336 pub options: Vec<(String, String)>,
1337 pub if_not_exists: bool,
1338}
1339
1340#[derive(Debug, Clone, Serialize, Deserialize)]
1341pub struct CreateForeignTable {
1342 pub name: String,
1343 pub server_name: String,
1344 pub columns: Vec<ColumnDef>,
1345 pub options: Vec<(String, String)>,
1346 pub if_not_exists: bool,
1347}
1348
1349#[derive(Debug, Clone, Serialize, Deserialize)]
1350pub struct CreateSequence {
1351 pub name: String,
1352 pub if_not_exists: bool,
1353 pub start: i64,
1354 pub increment: i64,
1355}
1356
1357#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1359pub enum SequenceRestart {
1360 #[default]
1362 Unchanged,
1363 FromStart,
1365 With(i64),
1367}
1368
1369fn deserialize_sequence_restart<'de, D>(deserializer: D) -> Result<SequenceRestart, D::Error>
1370where
1371 D: serde::Deserializer<'de>,
1372{
1373 #[derive(Deserialize)]
1374 enum Current {
1375 Unchanged,
1376 FromStart,
1377 With(i64),
1378 }
1379
1380 #[derive(Deserialize)]
1381 #[serde(untagged)]
1382 enum Representation {
1383 Current(Current),
1384 Legacy(Option<i64>),
1387 }
1388
1389 Ok(match Representation::deserialize(deserializer)? {
1390 Representation::Current(Current::Unchanged) | Representation::Legacy(None) => {
1391 SequenceRestart::Unchanged
1392 }
1393 Representation::Current(Current::FromStart) => SequenceRestart::FromStart,
1394 Representation::Current(Current::With(value)) | Representation::Legacy(Some(value)) => {
1395 SequenceRestart::With(value)
1396 }
1397 })
1398}
1399
1400#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1401pub struct AlterSequence {
1402 pub name: String,
1403 #[serde(default)]
1405 pub if_exists: bool,
1406 #[serde(default, deserialize_with = "deserialize_sequence_restart")]
1408 pub restart: SequenceRestart,
1409 pub increment: Option<i64>,
1410 pub start: Option<i64>,
1411}
1412
1413#[derive(Debug, Clone, Serialize, Deserialize)]
1414pub enum TransactionStmt {
1415 Begin,
1416 Commit,
1417 Rollback,
1418 Savepoint(String),
1419 ReleaseSavepoint(String),
1420 RollbackToSavepoint(String),
1421}
1422
1423#[cfg(test)]
1424mod tests {
1425 use super::{AlterSequence, ColumnType, SequenceRestart};
1426
1427 #[test]
1428 fn regclass_scalar_and_array_names_preserve_type_identity() {
1429 assert_eq!(
1430 ColumnType::from_sql_name("pg_catalog.regclass").unwrap(),
1431 ColumnType::Regclass
1432 );
1433 assert_eq!(
1434 ColumnType::from_sql_name("_regclass").unwrap(),
1435 ColumnType::Array(Box::new(ColumnType::Regclass))
1436 );
1437 assert_eq!(ColumnType::Regclass.sql_name(), "regclass");
1438 }
1439
1440 #[test]
1441 fn regtype_output_omits_type_modifiers() {
1442 assert_eq!(
1443 ColumnType::Varchar(Some(7)).regtype_name(),
1444 "character varying"
1445 );
1446 assert_eq!(
1447 ColumnType::Numeric {
1448 precision: Some(10),
1449 scale: Some(2),
1450 }
1451 .regtype_name(),
1452 "numeric"
1453 );
1454 assert_eq!(ColumnType::Vector(3).regtype_name(), "vector");
1455 assert_eq!(
1456 ColumnType::Array(Box::new(ColumnType::Character(4))).regtype_name(),
1457 "character[]"
1458 );
1459 }
1460
1461 #[test]
1462 fn alter_sequence_restart_reads_legacy_and_current_serde_shapes() {
1463 let omitted: AlterSequence = serde_json::from_str(r#"{"name":"s"}"#).unwrap();
1464 assert_eq!(omitted.restart, SequenceRestart::Unchanged);
1465
1466 let legacy_none: AlterSequence =
1467 serde_json::from_str(r#"{"name":"s","restart":null}"#).unwrap();
1468 assert_eq!(legacy_none.restart, SequenceRestart::Unchanged);
1469
1470 let legacy_value: AlterSequence =
1471 serde_json::from_str(r#"{"name":"s","restart":7}"#).unwrap();
1472 assert_eq!(legacy_value.restart, SequenceRestart::With(7));
1473
1474 let current = AlterSequence {
1475 name: "s".into(),
1476 restart: SequenceRestart::FromStart,
1477 ..AlterSequence::default()
1478 };
1479 let round_trip: AlterSequence =
1480 serde_json::from_str(&serde_json::to_string(¤t).unwrap()).unwrap();
1481 assert_eq!(round_trip.restart, SequenceRestart::FromStart);
1482 }
1483}