Skip to main content

uqa_sql/catalog/
sequence_functions.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Ordered argument and owner-column binding for sequence introspection functions.
8
9use crate::{
10    schema::sequences::ownership::{SequenceOwnerCatalog, SequenceOwnerColumnIdentity},
11    SQLError,
12};
13use uqa_core::Value;
14
15pub fn strict_sequence_oid(function: &str, arguments: &[Value]) -> Result<Option<i64>, SQLError> {
16    let [argument] = arguments else {
17        return Err(SQLError::BadArity {
18            name: function.into(),
19            expected: "1".into(),
20            actual: arguments.len(),
21        });
22    };
23    match argument {
24        Value::Null => Ok(None),
25        Value::Int(oid) => Ok(Some(*oid)),
26        value => Err(SQLError::TypeMismatch(format!(
27            "{function} requires oid or regclass, got {value:?}"
28        ))),
29    }
30}
31
32pub fn strict_sequence_regclass_oid(
33    function: &str,
34    arguments: &[Value],
35    resolve: &mut dyn FnMut(&str) -> Result<Option<i64>, SQLError>,
36) -> Result<Option<i64>, SQLError> {
37    let [argument] = arguments else {
38        return Err(SQLError::BadArity {
39            name: function.into(),
40            expected: "1".into(),
41            actual: arguments.len(),
42        });
43    };
44    match argument {
45        Value::Null => Ok(None),
46        Value::Int(oid) => Ok(Some(*oid)),
47        Value::Str(name) | Value::FixedChar(name) => {
48            resolve(name)?.map(Some).ok_or_else(|| SQLError::Routine {
49                sqlstate: "42P01".into(),
50                message: format!("relation \"{name}\" does not exist"),
51            })
52        }
53        value => Err(SQLError::TypeMismatch(format!(
54            "{function} requires regclass, got {value:?}"
55        ))),
56    }
57}
58
59pub fn serial_sequence_owner(
60    catalog: &dyn SequenceOwnerCatalog,
61    arguments: &[Value],
62) -> Result<Option<SequenceOwnerColumnIdentity>, SQLError> {
63    if arguments.len() != 2 {
64        return Err(SQLError::BadArity {
65            name: "pg_get_serial_sequence".into(),
66            expected: "2".into(),
67            actual: arguments.len(),
68        });
69    }
70    if arguments
71        .iter()
72        .any(|argument| matches!(argument, Value::Null))
73    {
74        return Ok(None);
75    }
76    let relation_name = match &arguments[0] {
77        Value::Str(value) | Value::FixedChar(value) => value,
78        other => {
79            return Err(SQLError::TypeMismatch(format!(
80                "pg_get_serial_sequence table name must be text, got {other:?}"
81            )))
82        }
83    };
84    let column_name = match &arguments[1] {
85        Value::Str(value) | Value::FixedChar(value) => value,
86        other => {
87            return Err(SQLError::TypeMismatch(format!(
88                "pg_get_serial_sequence column name must be text, got {other:?}"
89            )))
90        }
91    };
92    let Some((canonical, kind)) = catalog.resolve_owner_relation(relation_name)? else {
93        return Err(SQLError::Routine {
94            sqlstate: "42P01".into(),
95            message: format!("relation \"{relation_name}\" does not exist"),
96        });
97    };
98    let Some(owner_column) = crate::schema::sequences::ownership::sequence_owner_column_identity(
99        catalog,
100        &canonical,
101        kind,
102        column_name,
103    )?
104    else {
105        return Ok(None);
106    };
107    Ok(Some(owner_column))
108}
109
110pub mod value_error;