Skip to main content

rupg_catalog/
sequence.rs

1//! The sequences: the row of the file of a sequence, and the changes of `AlterSequence` and `process_owned_by`.
2
3use rupg_common::{Error, Result};
4
5use super::{Catalog, DepKind, ObjRef, PG_CLASS, SequenceInfo};
6
7/// The row of the file of a sequence, `FormData_pg_sequence_data`.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct SequenceData {
10    /// The last value that a call fetched, or the next value when `is_called` is false.
11    pub last_value: i64,
12    /// The number of values that the session can fetch before it writes the next WAL record.
13    pub log_cnt: i64,
14    /// False when the next call of `nextval` gives `last_value` itself.
15    pub is_called: bool,
16}
17
18impl SequenceData {
19    /// The row of a new file: `last_value` is the value that the next call gives.
20    pub fn new(last_value: i64) -> SequenceData {
21        SequenceData { last_value, log_cnt: 0, is_called: false }
22    }
23}
24
25impl Catalog {
26    /// The update of `pg_sequence` in `AlterSequence`. With `rewrite`, the sequence gets a new file with this row, as `RelationSetNewRelfilenumber` and `fill_seq_with_data` make it. The new file takes an OID, as `GetNewRelFileNumber` does.
27    pub fn alter_sequence(
28        &mut self,
29        oid: u32,
30        mut info: SequenceInfo,
31        rewrite: Option<SequenceData>,
32    ) -> Result<()> {
33        let file = match rewrite {
34            Some(data) => {
35                info.data = data;
36                self.new_oid()
37            }
38            None => info.file,
39        };
40        info.file = file;
41        let rel = self.relation_mut(oid)?;
42        let Some(old) = &mut rel.sequence else {
43            return Err(Error::internal(format!("cache lookup failed for sequence {oid}")));
44        };
45        *old = info;
46        Ok(())
47    }
48
49    /// `getIdentitySequence`: the sequence of an identity column. A partition has no sequence of its own, so its column uses the sequence of the column with the same name in the topmost partitioned table.
50    pub fn root_identity_sequence(&self, table: u32, column: i16) -> Option<u32> {
51        let mut root = table;
52        while let Some(parent) = self.relation(root).and_then(|r| r.partition_of.as_ref()) {
53            root = parent.parent;
54        }
55        if root == table {
56            return self.identity_sequence(table, column);
57        }
58        let name = &self.relation(table)?.column(column)?.name;
59        let number = self.relation(root)?.column_number(name)?;
60        self.identity_sequence(root, number)
61    }
62
63    /// The sequence that an identity column owns, which has an internal dependency on the column. The column of a partition owns no sequence.
64    pub fn identity_sequence(&self, table: u32, column: i16) -> Option<u32> {
65        let target = ObjRef::column(table, column);
66        self.depends
67            .iter()
68            .find(|d| {
69                d.referenced == target && d.object.class == PG_CLASS && d.kind == DepKind::Internal
70            })
71            .map(|d| d.object.oid)
72    }
73
74    /// `getOwnedSequences`: the sequences that a column of the table owns, by an automatic dependency of `OWNED BY` or `SERIAL` or by the internal dependency of an identity column, in the order of the columns.
75    pub fn owned_sequences(&self, table: u32) -> Vec<u32> {
76        let mut owned: Vec<(i32, u32)> = self
77            .depends
78            .iter()
79            .filter(|d| {
80                d.referenced.class == PG_CLASS
81                    && d.referenced.oid == table
82                    && d.object.class == PG_CLASS
83                    && d.object.sub == 0
84                    && matches!(d.kind, DepKind::Auto | DepKind::Internal)
85                    && self.relation(d.object.oid).is_some_and(|r| r.sequence.is_some())
86            })
87            .map(|d| (d.referenced.sub, d.object.oid))
88            .collect();
89        owned.sort_by_key(|&(sub, _)| sub);
90        owned.into_iter().map(|(_, oid)| oid).collect()
91    }
92
93    /// `process_owned_by`: the sequence loses its dependencies of `kind` on relations, and then gets one on the column when `column` is given.
94    pub fn set_owned_by(&mut self, sequence: u32, column: Option<(u32, i16)>, kind: DepKind) {
95        let me = ObjRef::new(PG_CLASS, sequence);
96        self.depends
97            .retain(|d| !(d.object == me && d.referenced.class == PG_CLASS && d.kind == kind));
98        if let Some((table, column)) = column {
99            self.depend(me, ObjRef::column(table, column), kind);
100        }
101    }
102}