1use super::definition::SequenceDefinition;
10use crate::ast::{
11 ColumnType, SequenceDataType, SequenceDeclaration, SequenceOptionValue, SequenceOwnership,
12};
13use crate::expr::integer_input::{parse_int8, IntegerInputError};
14use crate::SQLError;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct DeclaredSequence {
19 pub definition: SequenceDefinition,
20 pub current: i64,
22}
23
24pub fn declare_sequence(
26 declaration: &SequenceDeclaration,
27 data_type: &ColumnType,
28 identity: bool,
29) -> Result<DeclaredSequence, SQLError> {
30 read_sequence_options(declaration, Some(data_type), SequenceBase::New, identity)
31}
32
33pub fn alter_declared_sequence(
35 declaration: &SequenceDeclaration,
36 definition: &SequenceDefinition,
37 current: i64,
38 identity: bool,
39) -> Result<DeclaredSequence, SQLError> {
40 read_sequence_options(
41 declaration,
42 declaration.data_type.as_ref(),
43 SequenceBase::Existing {
44 definition,
45 current,
46 },
47 identity,
48 )
49}
50
51#[derive(Clone, Copy)]
53enum SequenceBase<'a> {
54 New,
55 Existing {
56 definition: &'a SequenceDefinition,
57 current: i64,
58 },
59}
60
61fn read_sequence_options(
63 declaration: &SequenceDeclaration,
64 written_type: Option<&ColumnType>,
65 base: SequenceBase<'_>,
66 identity: bool,
67) -> Result<DeclaredSequence, SQLError> {
68 let existing = match base {
69 SequenceBase::New => None,
70 SequenceBase::Existing {
71 definition,
72 current,
73 } => Some((definition, current)),
74 };
75 let definition = existing.map(|(definition, _)| definition);
76 let (data_type, reset_max, reset_min) = read_type(written_type, definition, identity)?;
77 let increment = match &declaration.increment {
78 Some(value) => {
79 let increment = sequence_option_integer("increment", value)?;
80 if increment == 0 {
81 return Err(invalid("INCREMENT must not be zero".into()));
82 }
83 increment
84 }
85 None => definition.map_or(1, |definition| definition.increment),
86 };
87 let cycle = declaration
88 .cycle
89 .or(definition.map(|definition| definition.cycle))
90 .unwrap_or(false);
91 let (min_value, max_value) = read_bounds(
92 declaration,
93 definition,
94 data_type,
95 increment,
96 (reset_min, reset_max),
97 )?;
98 let (start, current) = read_start(declaration, existing, increment, min_value, max_value)?;
99 let cache_size = match &declaration.cache {
100 Some(value) => {
101 let cache_size = sequence_option_integer("cache", value)?;
102 if cache_size <= 0 {
103 return Err(invalid(format!(
104 "CACHE ({cache_size}) must be greater than zero"
105 )));
106 }
107 cache_size
108 }
109 None => definition.map_or(1, |definition| definition.cache_size),
110 };
111 Ok(DeclaredSequence {
112 definition: SequenceDefinition {
113 start,
114 increment,
115 data_type,
116 min_value,
117 max_value,
118 cycle,
119 cache_size,
120 },
121 current,
122 })
123}
124
125fn read_type(
127 written: Option<&ColumnType>,
128 definition: Option<&SequenceDefinition>,
129 identity: bool,
130) -> Result<(SequenceDataType, bool, bool), SQLError> {
131 Ok(match (written, definition) {
132 (Some(written), Some(definition)) => {
133 let (old_min, old_max) = definition.data_type.bounds();
134 (
135 sequence_data_type(written, identity)?,
136 definition.max_value == old_max,
137 definition.min_value == old_min,
138 )
139 }
140 (Some(written), None) => (sequence_data_type(written, identity)?, false, false),
141 (None, Some(definition)) => (definition.data_type, false, false),
142 (None, None) => (SequenceDataType::BigInt, false, false),
143 })
144}
145
146fn read_bounds(
148 declaration: &SequenceDeclaration,
149 definition: Option<&SequenceDefinition>,
150 data_type: SequenceDataType,
151 increment: i64,
152 (reset_min, reset_max): (bool, bool),
153) -> Result<(i64, i64), SQLError> {
154 let (type_min, type_max) = data_type.bounds();
155 let max_value = match (&declaration.max_value, definition) {
156 (Some(value), _) if *value != SequenceOptionValue::Absent => {
157 sequence_option_integer("maxvalue", value)?
158 }
159 (Some(_), _) | (None, None) => {
160 if increment > 0 || reset_max {
161 type_max
162 } else {
163 -1
164 }
165 }
166 (None, Some(_)) if reset_max => type_max,
167 (None, Some(definition)) => definition.max_value,
168 };
169 if !(type_min..=type_max).contains(&max_value) {
170 return Err(invalid(format!(
171 "MAXVALUE ({max_value}) is out of range for sequence data type {}",
172 data_type.sql_name()
173 )));
174 }
175 let min_value = match (&declaration.min_value, definition) {
176 (Some(value), _) if *value != SequenceOptionValue::Absent => {
177 sequence_option_integer("minvalue", value)?
178 }
179 (Some(_), _) | (None, None) => {
180 if increment < 0 || reset_min {
181 type_min
182 } else {
183 1
184 }
185 }
186 (None, Some(_)) if reset_min => type_min,
187 (None, Some(definition)) => definition.min_value,
188 };
189 if !(type_min..=type_max).contains(&min_value) {
190 return Err(invalid(format!(
191 "MINVALUE ({min_value}) is out of range for sequence data type {}",
192 data_type.sql_name()
193 )));
194 }
195 if min_value >= max_value {
196 return Err(invalid(format!(
197 "MINVALUE ({min_value}) must be less than MAXVALUE ({max_value})"
198 )));
199 }
200 Ok((min_value, max_value))
201}
202
203fn read_start(
205 declaration: &SequenceDeclaration,
206 existing: Option<(&SequenceDefinition, i64)>,
207 increment: i64,
208 min_value: i64,
209 max_value: i64,
210) -> Result<(i64, i64), SQLError> {
211 let start = match (&declaration.start, existing) {
212 (Some(value), _) => sequence_option_integer("start", value)?,
213 (None, Some((definition, _))) => definition.start,
214 (None, None) if increment > 0 => min_value,
215 (None, None) => max_value,
216 };
217 if start < min_value {
218 return Err(invalid(format!(
219 "START value ({start}) cannot be less than MINVALUE ({min_value})"
220 )));
221 }
222 if start > max_value {
223 return Err(invalid(format!(
224 "START value ({start}) cannot be greater than MAXVALUE ({max_value})"
225 )));
226 }
227 let current = match (&declaration.restart, existing) {
228 (Some(SequenceOptionValue::Absent), _) | (None, None) => start,
229 (Some(value), _) => sequence_option_integer("restart", value)?,
230 (None, Some((_, current))) => current,
231 };
232 if current < min_value {
233 return Err(invalid(format!(
234 "RESTART value ({current}) cannot be less than MINVALUE ({min_value})"
235 )));
236 }
237 if current > max_value {
238 return Err(invalid(format!(
239 "RESTART value ({current}) cannot be greater than MAXVALUE ({max_value})"
240 )));
241 }
242 Ok((start, current))
243}
244
245pub fn sequence_ownership(names: &[String]) -> Result<SequenceOwnership, SQLError> {
247 use crate::compiler::render_relation_component;
248 match names {
249 [none] if none == "none" => Ok(SequenceOwnership::Unowned),
250 [] | [_] => Err(SQLError::Diagnostic {
251 sqlstate: "42601".into(),
252 message: "invalid OWNED BY option".into(),
253 detail: None,
254 hint: Some("Specify OWNED BY table.column or OWNED BY NONE.".into()),
255 }),
256 [table, column] => Ok(SequenceOwnership::Column {
257 table: render_relation_component(table),
258 column: column.clone(),
259 }),
260 [schema, table, column] => Ok(SequenceOwnership::Column {
261 table: format!(
262 "{}.{}",
263 render_relation_component(schema),
264 render_relation_component(table)
265 ),
266 column: column.clone(),
267 }),
268 _ => Err(SQLError::Unsupported(
269 "cross-database references are not implemented: OWNED BY".into(),
270 )),
271 }
272}
273
274fn sequence_data_type(
276 data_type: &ColumnType,
277 identity: bool,
278) -> Result<SequenceDataType, SQLError> {
279 match data_type {
280 ColumnType::SmallInteger => Ok(SequenceDataType::SmallInt),
281 ColumnType::Integer => Ok(SequenceDataType::Integer),
282 ColumnType::BigInteger => Ok(SequenceDataType::BigInt),
283 _ => Err(invalid(
284 if identity {
285 "identity column type must be smallint, integer, or bigint"
286 } else {
287 "sequence type must be smallint, integer, or bigint"
288 }
289 .into(),
290 )),
291 }
292}
293
294pub fn sequence_option_integer(name: &str, value: &SequenceOptionValue) -> Result<i64, SQLError> {
296 match value {
297 SequenceOptionValue::Integer(value) => Ok(*value),
298 SequenceOptionValue::Text(text) => parse_int8(text).map_err(|error| match error {
299 IntegerInputError::OutOfRange => SQLError::Routine {
300 sqlstate: "22003".into(),
301 message: format!("value \"{text}\" is out of range for type bigint"),
302 },
303 IntegerInputError::InvalidSyntax => SQLError::Routine {
304 sqlstate: "22P02".into(),
305 message: format!("invalid input syntax for type bigint: \"{text}\""),
306 },
307 }),
308 SequenceOptionValue::Absent => Err(SQLError::Routine {
309 sqlstate: "42601".into(),
310 message: format!("{name} requires a numeric value"),
311 }),
312 }
313}
314
315fn invalid(message: String) -> SQLError {
316 SQLError::Routine {
317 sqlstate: "22023".into(),
318 message,
319 }
320}
321
322#[cfg(test)]
323mod tests;