1use super::*;
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct SourceRange {
13 pub start: Position,
14 pub end: Position,
15}
16
17impl SourceRange {
18 pub const fn new(start: Position, end: Position) -> Self {
19 Self { start, end }
20 }
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub struct ObjectName {
25 pub components: Vec<Identifier>,
26}
27
28impl ObjectName {
29 pub fn new(components: Vec<Identifier>) -> Self {
30 Self { components }
31 }
32}
33
34impl fmt::Display for ObjectName {
35 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
36 for (index, component) in self.components.iter().enumerate() {
37 if index > 0 {
38 formatter.write_str(".")?;
39 }
40 write!(formatter, "{component}")?;
41 }
42 Ok(())
43 }
44}
45
46#[derive(Debug, Clone, PartialEq)]
47pub enum ProceduralType {
48 Scalar(SmartString),
49 RowType(ObjectName),
50}
51
52impl fmt::Display for ProceduralType {
53 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::Scalar(name) => formatter.write_str(name),
56 Self::RowType(table) => write!(formatter, "{table}%ROWTYPE"),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum RoutineArgumentMode {
63 In,
64 Out,
65 InOut,
66}
67
68impl fmt::Display for RoutineArgumentMode {
69 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70 formatter.write_str(match self {
71 Self::In => "IN",
72 Self::Out => "OUT",
73 Self::InOut => "INOUT",
74 })
75 }
76}
77
78#[derive(Debug, Clone, PartialEq)]
79pub struct RoutineArgumentSyntax {
80 pub token: Token,
81 pub mode: RoutineArgumentMode,
82 pub name: Identifier,
83 pub data_type: ProceduralType,
84 pub nullable: bool,
85 pub default: Option<Expression>,
86 pub span: SourceRange,
87}
88
89impl fmt::Display for RoutineArgumentSyntax {
90 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
91 if self.mode != RoutineArgumentMode::In {
92 write!(formatter, "{} ", self.mode)?;
93 }
94 write!(formatter, "{} {}", self.name, self.data_type)?;
95 if !self.nullable {
96 formatter.write_str(" NOT NULL")?;
97 }
98 if let Some(default) = &self.default {
99 write!(formatter, " DEFAULT {default}")?;
100 }
101 Ok(())
102 }
103}
104
105#[derive(Debug, Clone, PartialEq)]
106pub struct ResultColumnSyntax {
107 pub name: Identifier,
108 pub data_type: ProceduralType,
109 pub nullable: bool,
110}
111
112impl fmt::Display for ResultColumnSyntax {
113 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
114 write!(formatter, "{} {}", self.name, self.data_type)?;
115 if !self.nullable {
116 formatter.write_str(" NOT NULL")?;
117 }
118 Ok(())
119 }
120}
121
122#[derive(Debug, Clone, PartialEq)]
123pub enum RoutineReturnSyntax {
124 Scalar {
125 data_type: ProceduralType,
126 nullable: bool,
127 },
128 Table(Vec<ResultColumnSyntax>),
129 Trigger,
130}
131
132impl fmt::Display for RoutineReturnSyntax {
133 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
134 match self {
135 Self::Scalar {
136 data_type,
137 nullable,
138 } => {
139 write!(formatter, "{data_type}")?;
140 if !nullable {
141 formatter.write_str(" NOT NULL")?;
142 }
143 Ok(())
144 }
145 Self::Table(columns) => {
146 formatter.write_str("TABLE (")?;
147 for (index, column) in columns.iter().enumerate() {
148 if index > 0 {
149 formatter.write_str(", ")?;
150 }
151 write!(formatter, "{column}")?;
152 }
153 formatter.write_str(")")
154 }
155 Self::Trigger => formatter.write_str("TRIGGER"),
156 }
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub enum RoutineVolatilitySyntax {
162 Immutable,
163 Stable,
164 Volatile,
165}
166
167impl fmt::Display for RoutineVolatilitySyntax {
168 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
169 formatter.write_str(match self {
170 Self::Immutable => "IMMUTABLE",
171 Self::Stable => "STABLE",
172 Self::Volatile => "VOLATILE",
173 })
174 }
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub enum RoutineSecuritySyntax {
179 Invoker,
180 Definer,
181}
182
183impl fmt::Display for RoutineSecuritySyntax {
184 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
185 formatter.write_str(match self {
186 Self::Invoker => "SECURITY INVOKER",
187 Self::Definer => "SECURITY DEFINER",
188 })
189 }
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum RoutineKindSyntax {
194 Function,
195 Procedure,
196}
197
198#[derive(Debug, Clone, PartialEq)]
199pub struct NativeFunctionBindingSyntax {
200 pub extension: ObjectName,
201 pub local_id: SmartString,
202}
203
204#[derive(Debug, Clone, PartialEq)]
205pub struct CreateRoutineStatement {
206 pub token: Token,
207 pub or_replace: bool,
208 pub kind: RoutineKindSyntax,
209 pub name: ObjectName,
210 pub arguments: Vec<RoutineArgumentSyntax>,
211 pub returns: Option<RoutineReturnSyntax>,
212 pub volatility: Option<RoutineVolatilitySyntax>,
213 pub security: RoutineSecuritySyntax,
214 pub search_path: Vec<ObjectName>,
215 pub resource_policy: Option<ObjectName>,
216 pub body: Option<ProceduralBlock>,
217 pub native: Option<NativeFunctionBindingSyntax>,
218 pub normalized_source: String,
219 pub span: SourceRange,
220}
221
222impl fmt::Display for CreateRoutineStatement {
223 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
224 formatter.write_str("CREATE ")?;
225 if self.or_replace {
226 formatter.write_str("OR REPLACE ")?;
227 }
228 let kind = match self.kind {
229 RoutineKindSyntax::Function => "FUNCTION",
230 RoutineKindSyntax::Procedure => "PROCEDURE",
231 };
232 write!(formatter, "{kind} {}(", self.name)?;
233 for (index, argument) in self.arguments.iter().enumerate() {
234 if index > 0 {
235 formatter.write_str(", ")?;
236 }
237 write!(formatter, "{argument}")?;
238 }
239 formatter.write_str(")")?;
240 if let Some(returns) = &self.returns {
241 write!(formatter, " RETURNS {returns}")?;
242 }
243 if let Some(native) = &self.native {
244 write!(
245 formatter,
246 " LANGUAGE NATIVE FROM EXTENSION {} AS '{}'",
247 native.extension,
248 escape_sql_string(native.local_id.as_str())
249 )?;
250 return Ok(());
251 }
252 formatter.write_str(" LANGUAGE RADIX")?;
253 if let Some(volatility) = self.volatility {
254 write!(formatter, " {volatility}")?;
255 }
256 write!(formatter, " {}", self.security)?;
257 if !self.search_path.is_empty() {
258 formatter.write_str(" SEARCH PATH (")?;
259 for (index, namespace) in self.search_path.iter().enumerate() {
260 if index > 0 {
261 formatter.write_str(", ")?;
262 }
263 write!(formatter, "{namespace}")?;
264 }
265 formatter.write_str(")")?;
266 }
267 if let Some(policy) = &self.resource_policy {
268 write!(formatter, " RESOURCE POLICY {policy}")?;
269 }
270 write!(
271 formatter,
272 " AS {}",
273 self.body
274 .as_ref()
275 .expect("RADIX routine requires a procedural body")
276 )
277 }
278}
279
280#[derive(Debug, Clone, Copy, PartialEq, Eq)]
281pub enum TriggerTimingSyntax {
282 Before,
283 After,
284}
285
286impl fmt::Display for TriggerTimingSyntax {
287 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
288 formatter.write_str(match self {
289 Self::Before => "BEFORE",
290 Self::After => "AFTER",
291 })
292 }
293}
294
295#[derive(Debug, Clone, Copy, PartialEq, Eq)]
296pub enum TriggerLevelSyntax {
297 Row,
298 Statement,
299}
300
301impl fmt::Display for TriggerLevelSyntax {
302 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
303 formatter.write_str(match self {
304 Self::Row => "ROW",
305 Self::Statement => "STATEMENT",
306 })
307 }
308}
309
310#[derive(Debug, Clone, PartialEq)]
311pub enum TriggerEventSyntax {
312 Insert,
313 Update { columns: Vec<Identifier> },
314 Delete,
315}
316
317impl fmt::Display for TriggerEventSyntax {
318 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
319 match self {
320 Self::Insert => formatter.write_str("INSERT"),
321 Self::Update { columns } => {
322 formatter.write_str("UPDATE")?;
323 if !columns.is_empty() {
324 formatter.write_str(" OF ")?;
325 write_identifiers(formatter, columns)?;
326 }
327 Ok(())
328 }
329 Self::Delete => formatter.write_str("DELETE"),
330 }
331 }
332}
333
334#[derive(Debug, Clone, PartialEq)]
335pub struct RoutineSignatureSyntax {
336 pub name: ObjectName,
337 pub argument_types: Vec<ProceduralType>,
338}
339
340impl fmt::Display for RoutineSignatureSyntax {
341 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
342 write!(formatter, "{}(", self.name)?;
343 for (index, argument_type) in self.argument_types.iter().enumerate() {
344 if index > 0 {
345 formatter.write_str(", ")?;
346 }
347 write!(formatter, "{argument_type}")?;
348 }
349 formatter.write_str(")")
350 }
351}
352
353#[derive(Debug, Clone, PartialEq)]
354pub struct CreateTriggerStatement {
355 pub token: Token,
356 pub or_replace: bool,
357 pub name: ObjectName,
358 pub timing: TriggerTimingSyntax,
359 pub events: Vec<TriggerEventSyntax>,
360 pub table: ObjectName,
361 pub level: TriggerLevelSyntax,
362 pub priority: i32,
363 pub when: Option<Expression>,
364 pub function: RoutineSignatureSyntax,
365 pub span: SourceRange,
366}
367
368impl fmt::Display for CreateTriggerStatement {
369 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
370 formatter.write_str("CREATE ")?;
371 if self.or_replace {
372 formatter.write_str("OR REPLACE ")?;
373 }
374 write!(formatter, "TRIGGER {} {} ", self.name, self.timing)?;
375 for (index, event) in self.events.iter().enumerate() {
376 if index > 0 {
377 formatter.write_str(" OR ")?;
378 }
379 write!(formatter, "{event}")?;
380 }
381 write!(
382 formatter,
383 " ON {} FOR EACH {} PRIORITY {}",
384 self.table, self.level, self.priority
385 )?;
386 if let Some(condition) = &self.when {
387 write!(formatter, " WHEN ({condition})")?;
388 }
389 write!(formatter, " EXECUTE FUNCTION {}", self.function)
390 }
391}
392
393#[derive(Debug, Clone, PartialEq)]
394pub enum JobScheduleSyntax {
395 Every(Expression),
396 At(Expression),
397}
398
399#[derive(Debug, Clone, PartialEq)]
400pub struct CreateJobStatement {
401 pub token: Token,
402 pub name: ObjectName,
403 pub schedule: JobScheduleSyntax,
404 pub principal: ObjectName,
405 pub procedure: ObjectName,
406 pub arguments: Vec<CallArgumentSyntax>,
407 pub enabled: bool,
408 pub span: SourceRange,
409}
410
411impl fmt::Display for CreateJobStatement {
412 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
413 write!(formatter, "CREATE JOB {} SCHEDULE ", self.name)?;
414 match &self.schedule {
415 JobScheduleSyntax::Every(interval) => write!(formatter, "EVERY {interval}")?,
416 JobScheduleSyntax::At(timestamp) => write!(formatter, "AT {timestamp}")?,
417 }
418 write!(
419 formatter,
420 " RUN AS {} CALL {}(",
421 self.principal, self.procedure
422 )?;
423 for (index, argument) in self.arguments.iter().enumerate() {
424 if index > 0 {
425 formatter.write_str(", ")?;
426 }
427 write!(formatter, "{argument}")?;
428 }
429 formatter.write_str(if self.enabled {
430 ") ENABLE"
431 } else {
432 ") DISABLE"
433 })
434 }
435}
436
437#[derive(Debug, Clone, PartialEq)]
438pub struct DropRoutineStatement {
439 pub token: Token,
440 pub kind: RoutineKindSyntax,
441 pub signature: RoutineSignatureSyntax,
442 pub if_exists: bool,
443 pub behavior: DropBehaviorSyntax,
444}
445
446impl fmt::Display for DropRoutineStatement {
447 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
448 formatter.write_str(match self.kind {
449 RoutineKindSyntax::Function => "DROP FUNCTION ",
450 RoutineKindSyntax::Procedure => "DROP PROCEDURE ",
451 })?;
452 if self.if_exists {
453 formatter.write_str("IF EXISTS ")?;
454 }
455 write!(formatter, "{} {}", self.signature, self.behavior)
456 }
457}
458
459#[derive(Debug, Clone, PartialEq)]
460pub struct DropTriggerStatement {
461 pub token: Token,
462 pub name: ObjectName,
463 pub table: ObjectName,
464 pub if_exists: bool,
465 pub behavior: DropBehaviorSyntax,
466}
467
468impl fmt::Display for DropTriggerStatement {
469 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
470 formatter.write_str("DROP TRIGGER ")?;
471 if self.if_exists {
472 formatter.write_str("IF EXISTS ")?;
473 }
474 write!(
475 formatter,
476 "{} ON {} {}",
477 self.name, self.table, self.behavior
478 )
479 }
480}
481
482#[derive(Debug, Clone, PartialEq)]
483pub struct DropJobStatement {
484 pub token: Token,
485 pub name: ObjectName,
486 pub if_exists: bool,
487 pub behavior: DropBehaviorSyntax,
488}
489
490impl fmt::Display for DropJobStatement {
491 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
492 formatter.write_str("DROP JOB ")?;
493 if self.if_exists {
494 formatter.write_str("IF EXISTS ")?;
495 }
496 write!(formatter, "{} {}", self.name, self.behavior)
497 }
498}
499
500#[derive(Debug, Clone, PartialEq)]
501pub struct AlterJobStatement {
502 pub token: Token,
503 pub name: ObjectName,
504 pub enabled: bool,
505}
506
507impl fmt::Display for AlterJobStatement {
508 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
509 write!(
510 formatter,
511 "ALTER JOB {} {}",
512 self.name,
513 if self.enabled { "ENABLE" } else { "DISABLE" }
514 )
515 }
516}
517
518fn write_identifiers(
519 formatter: &mut fmt::Formatter<'_>,
520 identifiers: &[Identifier],
521) -> fmt::Result {
522 for (index, identifier) in identifiers.iter().enumerate() {
523 if index > 0 {
524 formatter.write_str(", ")?;
525 }
526 write!(formatter, "{identifier}")?;
527 }
528 Ok(())
529}
530
531#[derive(Debug, Clone, PartialEq)]
532pub enum ProceduralDeclaration {
533 Variable {
534 token: Token,
535 name: Identifier,
536 constant: bool,
537 data_type: ProceduralType,
538 nullable: bool,
539 initializer: Option<Expression>,
540 span: SourceRange,
541 },
542 Collection {
543 token: Token,
544 name: Identifier,
545 element_type: ProceduralType,
546 capacity: u32,
547 span: SourceRange,
548 },
549 Cursor {
550 token: Token,
551 name: Identifier,
552 arguments: Vec<RoutineArgumentSyntax>,
553 query: Box<Statement>,
554 span: SourceRange,
555 },
556}
557
558impl fmt::Display for ProceduralDeclaration {
559 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
560 match self {
561 Self::Variable {
562 name,
563 constant,
564 data_type,
565 nullable,
566 initializer,
567 ..
568 } => {
569 write!(formatter, "{name} ")?;
570 if *constant {
571 formatter.write_str("CONSTANT ")?;
572 }
573 write!(formatter, "{data_type}")?;
574 if !nullable {
575 formatter.write_str(" NOT NULL")?;
576 }
577 if let Some(initializer) = initializer {
578 write!(formatter, " := {initializer}")?;
579 }
580 Ok(())
581 }
582 Self::Collection {
583 name,
584 element_type,
585 capacity,
586 ..
587 } => write!(formatter, "{name} ARRAY<{element_type}, {capacity}>"),
588 Self::Cursor {
589 name,
590 arguments,
591 query,
592 ..
593 } => {
594 write!(formatter, "CURSOR {name}(")?;
595 for (index, argument) in arguments.iter().enumerate() {
596 if index > 0 {
597 formatter.write_str(", ")?;
598 }
599 write!(formatter, "{} {}", argument.name, argument.data_type)?;
600 }
601 write!(formatter, ") FOR {query}")
602 }
603 }
604 }
605}
606
607#[derive(Debug, Clone, PartialEq)]
608pub struct CallArgumentSyntax {
609 pub name: Option<Identifier>,
610 pub value: Expression,
611}
612
613#[derive(Debug, Clone, PartialEq)]
614pub struct CallStatement {
615 pub token: Token,
616 pub routine: ObjectName,
617 pub arguments: Vec<CallArgumentSyntax>,
618}
619
620impl fmt::Display for CallStatement {
621 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
622 write!(formatter, "CALL {}(", self.routine)?;
623 for (index, argument) in self.arguments.iter().enumerate() {
624 if index > 0 {
625 formatter.write_str(", ")?;
626 }
627 write!(formatter, "{argument}")?;
628 }
629 formatter.write_str(")")
630 }
631}
632
633impl fmt::Display for CallArgumentSyntax {
634 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
635 if let Some(name) = &self.name {
636 write!(formatter, "{name} => ")?;
637 }
638 write!(formatter, "{}", self.value)
639 }
640}
641
642#[derive(Debug, Clone, PartialEq)]
643pub enum AssignmentTargetSyntax {
644 Name(ObjectName),
645 Index {
646 collection: ObjectName,
647 index: Expression,
648 },
649}
650
651impl fmt::Display for AssignmentTargetSyntax {
652 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
653 match self {
654 Self::Name(name) => write!(formatter, "{name}"),
655 Self::Index { collection, index } => write!(formatter, "{collection}[{index}]"),
656 }
657 }
658}
659
660#[derive(Debug, Clone, PartialEq)]
661pub struct ProceduralSqlStatement {
662 pub statement: Box<Statement>,
663 pub into: Vec<Identifier>,
664 pub strict: bool,
665 pub span: SourceRange,
666}
667
668#[derive(Debug, Clone, PartialEq)]
669pub enum ReturnSyntax {
670 Void,
671 Value(Expression),
672 Next(Vec<Expression>),
673 Query(Box<Statement>),
674}
675
676#[derive(Debug, Clone, PartialEq)]
677pub enum LoopControlKind {
678 Exit,
679 Continue,
680}
681
682#[derive(Debug, Clone, PartialEq)]
683pub enum ForSourceSyntax {
684 Numeric {
685 reverse: bool,
686 start: Box<Expression>,
687 end: Box<Expression>,
688 step: Option<Box<Expression>>,
689 },
690 Query(Box<Statement>),
691}
692
693#[derive(Debug, Clone, PartialEq)]
694pub struct CaseArmSyntax {
695 pub condition: Expression,
696 pub statements: Vec<ProceduralStatement>,
697}
698
699#[derive(Debug, Clone, PartialEq)]
700pub struct DynamicExecuteSyntax {
701 pub source: Expression,
702 pub into: Vec<Identifier>,
703 pub strict: bool,
704 pub using: Vec<Expression>,
705}
706
707#[derive(Debug, Clone, PartialEq)]
708pub enum ProceduralStatement {
709 Assignment {
710 token: Token,
711 target: AssignmentTargetSyntax,
712 value: Expression,
713 span: SourceRange,
714 },
715 Call {
716 token: Token,
717 routine: ObjectName,
718 arguments: Vec<CallArgumentSyntax>,
719 span: SourceRange,
720 },
721 Perform {
722 token: Token,
723 expression: Expression,
724 span: SourceRange,
725 },
726 If {
727 token: Token,
728 branches: Vec<(Expression, Vec<ProceduralStatement>)>,
729 otherwise: Vec<ProceduralStatement>,
730 span: SourceRange,
731 },
732 Case {
733 token: Token,
734 operand: Option<Expression>,
735 arms: Vec<CaseArmSyntax>,
736 otherwise: Vec<ProceduralStatement>,
737 span: SourceRange,
738 },
739 Loop {
740 token: Token,
741 statements: Vec<ProceduralStatement>,
742 span: SourceRange,
743 },
744 While {
745 token: Token,
746 condition: Expression,
747 statements: Vec<ProceduralStatement>,
748 span: SourceRange,
749 },
750 For {
751 token: Token,
752 variable: Identifier,
753 source: ForSourceSyntax,
754 statements: Vec<ProceduralStatement>,
755 span: SourceRange,
756 },
757 LoopControl {
758 token: Token,
759 kind: LoopControlKind,
760 condition: Option<Expression>,
761 span: SourceRange,
762 },
763 Return {
764 token: Token,
765 value: ReturnSyntax,
766 span: SourceRange,
767 },
768 Sql(ProceduralSqlStatement),
769 DynamicExecute {
770 token: Token,
771 execute: DynamicExecuteSyntax,
772 span: SourceRange,
773 },
774 OpenCursor {
775 token: Token,
776 cursor: Identifier,
777 arguments: Vec<Expression>,
778 span: SourceRange,
779 },
780 FetchCursor {
781 token: Token,
782 cursor: Identifier,
783 into: Vec<Identifier>,
784 span: SourceRange,
785 },
786 CloseCursor {
787 token: Token,
788 cursor: Identifier,
789 span: SourceRange,
790 },
791 Raise {
792 token: Token,
793 kind: Option<Identifier>,
794 arguments: Vec<Expression>,
795 span: SourceRange,
796 },
797 Block(Box<ProceduralBlock>),
798}
799
800#[derive(Debug, Clone, PartialEq)]
801pub enum ExceptionPatternSyntax {
802 Named(Identifier),
803 Others,
804}
805
806impl fmt::Display for ExceptionPatternSyntax {
807 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
808 match self {
809 Self::Named(name) => write!(formatter, "{name}"),
810 Self::Others => formatter.write_str("OTHERS"),
811 }
812 }
813}
814
815#[derive(Debug, Clone, PartialEq)]
816pub struct ExceptionHandlerSyntax {
817 pub token: Token,
818 pub patterns: Vec<ExceptionPatternSyntax>,
819 pub alias: Option<Identifier>,
820 pub statements: Vec<ProceduralStatement>,
821 pub span: SourceRange,
822}
823
824#[derive(Debug, Clone, PartialEq)]
825pub struct ProceduralBlock {
826 pub token: Token,
827 pub declarations: Vec<ProceduralDeclaration>,
828 pub statements: Vec<ProceduralStatement>,
829 pub handlers: Vec<ExceptionHandlerSyntax>,
830 pub span: SourceRange,
831}
832
833impl fmt::Display for ProceduralBlock {
834 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
835 if !self.declarations.is_empty() {
836 formatter.write_str("DECLARE ")?;
837 for declaration in &self.declarations {
838 write!(formatter, "{declaration}; ")?;
839 }
840 }
841 formatter.write_str("BEGIN ")?;
842 for statement in &self.statements {
843 write!(formatter, "{statement}; ")?;
844 }
845 if !self.handlers.is_empty() {
846 formatter.write_str("EXCEPTION ")?;
847 for handler in &self.handlers {
848 formatter.write_str("WHEN ")?;
849 for (index, pattern) in handler.patterns.iter().enumerate() {
850 if index > 0 {
851 formatter.write_str(" OR ")?;
852 }
853 write!(formatter, "{pattern}")?;
854 }
855 if let Some(alias) = &handler.alias {
856 write!(formatter, " AS {alias}")?;
857 }
858 formatter.write_str(" THEN ")?;
859 for statement in &handler.statements {
860 write!(formatter, "{statement}; ")?;
861 }
862 }
863 }
864 formatter.write_str("END")
865 }
866}
867
868impl fmt::Display for ProceduralStatement {
869 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
870 match self {
871 Self::Assignment { target, value, .. } => write!(formatter, "{target} := {value}"),
872 Self::Call {
873 routine, arguments, ..
874 } => {
875 write!(formatter, "CALL {routine}(")?;
876 for (index, argument) in arguments.iter().enumerate() {
877 if index > 0 {
878 formatter.write_str(", ")?;
879 }
880 write!(formatter, "{argument}")?;
881 }
882 formatter.write_str(")")
883 }
884 Self::Perform { expression, .. } => write!(formatter, "PERFORM {expression}"),
885 Self::If {
886 branches,
887 otherwise,
888 ..
889 } => {
890 for (index, (condition, statements)) in branches.iter().enumerate() {
891 if index == 0 {
892 write!(formatter, "IF {condition} THEN ")?;
893 } else {
894 write!(formatter, "ELSIF {condition} THEN ")?;
895 }
896 for statement in statements {
897 write!(formatter, "{statement}; ")?;
898 }
899 }
900 if !otherwise.is_empty() {
901 formatter.write_str("ELSE ")?;
902 for statement in otherwise {
903 write!(formatter, "{statement}; ")?;
904 }
905 }
906 formatter.write_str("END IF")
907 }
908 Self::Case {
909 operand,
910 arms,
911 otherwise,
912 ..
913 } => {
914 formatter.write_str("CASE")?;
915 if let Some(operand) = operand {
916 write!(formatter, " {operand}")?;
917 }
918 formatter.write_str(" ")?;
919 for arm in arms {
920 write!(formatter, "WHEN {} THEN ", arm.condition)?;
921 for statement in &arm.statements {
922 write!(formatter, "{statement}; ")?;
923 }
924 }
925 if !otherwise.is_empty() {
926 formatter.write_str("ELSE ")?;
927 for statement in otherwise {
928 write!(formatter, "{statement}; ")?;
929 }
930 }
931 formatter.write_str("END CASE")
932 }
933 Self::Loop { statements, .. } => {
934 formatter.write_str("LOOP ")?;
935 for statement in statements {
936 write!(formatter, "{statement}; ")?;
937 }
938 formatter.write_str("END LOOP")
939 }
940 Self::While {
941 condition,
942 statements,
943 ..
944 } => {
945 write!(formatter, "WHILE {condition} LOOP ")?;
946 for statement in statements {
947 write!(formatter, "{statement}; ")?;
948 }
949 formatter.write_str("END LOOP")
950 }
951 Self::For {
952 variable,
953 source,
954 statements,
955 ..
956 } => {
957 write!(formatter, "FOR {variable} IN ")?;
958 match source {
959 ForSourceSyntax::Numeric {
960 reverse,
961 start,
962 end,
963 step,
964 } => {
965 if *reverse {
966 formatter.write_str("REVERSE ")?;
967 }
968 write!(formatter, "{start} TO {end}")?;
969 if let Some(step) = step {
970 write!(formatter, " BY {step}")?;
971 }
972 }
973 ForSourceSyntax::Query(query) => write!(formatter, "({query})")?,
974 }
975 formatter.write_str(" LOOP ")?;
976 for statement in statements {
977 write!(formatter, "{statement}; ")?;
978 }
979 formatter.write_str("END LOOP")
980 }
981 Self::LoopControl {
982 kind, condition, ..
983 } => {
984 formatter.write_str(match kind {
985 LoopControlKind::Exit => "EXIT",
986 LoopControlKind::Continue => "CONTINUE",
987 })?;
988 if let Some(condition) = condition {
989 write!(formatter, " WHEN {condition}")?;
990 }
991 Ok(())
992 }
993 Self::Return { value, .. } => match value {
994 ReturnSyntax::Void => formatter.write_str("RETURN"),
995 ReturnSyntax::Value(value) => write!(formatter, "RETURN {value}"),
996 ReturnSyntax::Next(values) => {
997 formatter.write_str("RETURN NEXT (")?;
998 for (index, value) in values.iter().enumerate() {
999 if index > 0 {
1000 formatter.write_str(", ")?;
1001 }
1002 write!(formatter, "{value}")?;
1003 }
1004 formatter.write_str(")")
1005 }
1006 ReturnSyntax::Query(query) => write!(formatter, "RETURN QUERY {query}"),
1007 },
1008 Self::Sql(sql) => {
1009 let rendered = sql.statement.to_string();
1010 if sql.into.is_empty() {
1011 return formatter.write_str(&rendered);
1012 }
1013 if matches!(sql.statement.as_ref(), Statement::Select(_)) {
1014 if let Some(offset) = top_level_from_offset(&rendered) {
1015 formatter.write_str(rendered[..offset].trim_end())?;
1016 write_into_targets(formatter, sql.strict, &sql.into)?;
1017 formatter.write_str(" ")?;
1018 formatter.write_str(&rendered[offset..])?;
1019 } else {
1020 formatter.write_str(&rendered)?;
1021 write_into_targets(formatter, sql.strict, &sql.into)?;
1022 }
1023 } else {
1024 formatter.write_str(&rendered)?;
1025 write_into_targets(formatter, sql.strict, &sql.into)?;
1026 }
1027 Ok(())
1028 }
1029 Self::DynamicExecute { execute, .. } => {
1030 write!(formatter, "EXECUTE {}", execute.source)?;
1031 if !execute.into.is_empty() {
1032 formatter.write_str(" INTO ")?;
1033 if execute.strict {
1034 formatter.write_str("STRICT ")?;
1035 }
1036 for (index, target) in execute.into.iter().enumerate() {
1037 if index > 0 {
1038 formatter.write_str(", ")?;
1039 }
1040 write!(formatter, "{target}")?;
1041 }
1042 }
1043 if !execute.using.is_empty() {
1044 formatter.write_str(" USING ")?;
1045 for (index, argument) in execute.using.iter().enumerate() {
1046 if index > 0 {
1047 formatter.write_str(", ")?;
1048 }
1049 write!(formatter, "{argument}")?;
1050 }
1051 }
1052 Ok(())
1053 }
1054 Self::OpenCursor {
1055 cursor, arguments, ..
1056 } => {
1057 write!(formatter, "OPEN {cursor}(")?;
1058 for (index, argument) in arguments.iter().enumerate() {
1059 if index > 0 {
1060 formatter.write_str(", ")?;
1061 }
1062 write!(formatter, "{argument}")?;
1063 }
1064 formatter.write_str(")")
1065 }
1066 Self::FetchCursor { cursor, into, .. } => {
1067 write!(formatter, "FETCH {cursor} INTO ")?;
1068 for (index, target) in into.iter().enumerate() {
1069 if index > 0 {
1070 formatter.write_str(", ")?;
1071 }
1072 write!(formatter, "{target}")?;
1073 }
1074 Ok(())
1075 }
1076 Self::CloseCursor { cursor, .. } => write!(formatter, "CLOSE {cursor}"),
1077 Self::Raise {
1078 kind, arguments, ..
1079 } => {
1080 formatter.write_str("RAISE")?;
1081 if let Some(kind) = kind {
1082 write!(formatter, " {kind}(")?;
1083 for (index, argument) in arguments.iter().enumerate() {
1084 if index > 0 {
1085 formatter.write_str(", ")?;
1086 }
1087 write!(formatter, "{argument}")?;
1088 }
1089 formatter.write_str(")")?;
1090 }
1091 Ok(())
1092 }
1093 Self::Block(block) => write!(formatter, "{block}"),
1094 }
1095 }
1096}
1097
1098fn write_into_targets(
1099 formatter: &mut fmt::Formatter<'_>,
1100 strict: bool,
1101 targets: &[Identifier],
1102) -> fmt::Result {
1103 formatter.write_str(" INTO ")?;
1104 if strict {
1105 formatter.write_str("STRICT ")?;
1106 }
1107 for (index, target) in targets.iter().enumerate() {
1108 if index > 0 {
1109 formatter.write_str(", ")?;
1110 }
1111 write!(formatter, "{target}")?;
1112 }
1113 Ok(())
1114}
1115
1116fn top_level_from_offset(sql: &str) -> Option<usize> {
1117 let mut lexer = crate::Lexer::new(sql);
1118 let mut depth = 0usize;
1119 loop {
1120 let token = lexer.next_token();
1121 if token.is_eof() {
1122 return None;
1123 }
1124 if token.is_punctuator("(") {
1125 depth += 1;
1126 } else if token.is_punctuator(")") {
1127 depth = depth.saturating_sub(1);
1128 } else if depth == 0 && token.is_keyword("FROM") {
1129 return Some(token.position.offset);
1130 }
1131 }
1132}