1use super::{AbendId, PlaceId, SymId};
5use crate::sql::{HostType, fingerprint};
6use crate::{codec_enum, codec_struct};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct SqlEntry<P = PlaceId, S = SymId> {
13 pub ordinal: u32,
14 pub verb: S,
16 pub statement: SqlStatement<P, S>,
17 pub text: S,
20 pub fingerprint: u32,
21 pub with_hold: bool,
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
27pub enum SqlStatement<P = PlaceId, S = SymId> {
28 Query { inputs: Vec<HostPlace<P>>, into: Vec<HostPlace<P>> },
29 Change { delete: bool, inputs: Vec<HostPlace<P>>, current_of: Option<S> },
30 Open { cursor: S, inputs: Vec<HostPlace<P>> },
31 Fetch { cursor: S, into: Vec<HostPlace<P>> },
32 Close { cursor: S },
33 Commit,
34 Rollback,
35 Prepare { name: S, source: Vec<HostPlace<P>> },
38 ExecuteImmediate { source: Vec<HostPlace<P>> },
39 Execute { name: S, inputs: Vec<HostPlace<P>> },
41 OpenPrepared { cursor: S, statement: S, inputs: Vec<HostPlace<P>> },
43 Declaration,
45 Unsupported(S),
47 Connect { what: S, location: Vec<HostPlace<P>> },
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct HostPlace<P = PlaceId> {
56 pub var: P,
57 pub member: Option<(u32, u32)>,
58 pub ty: Result<HostType, AbendId>,
60 pub indicator: Option<(P, u32)>,
61}
62
63#[derive(Clone, Debug, Default, PartialEq, Eq)]
65pub struct Sqlca<P = PlaceId> {
66 pub fields: Vec<(SqlcaField, P, HostType)>,
67}
68
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub enum SqlcaField {
71 CaId,
72 CaBc,
73 Code,
74 ErrMl,
75 ErrMc,
76 ErrP,
77 State,
78 ErrD(u8),
80 Warn(u8),
82}
83
84codec_struct!(SqlEntry { ordinal, verb, statement, text, fingerprint, with_hold });
85codec_enum!(SqlStatement {
86 Query { inputs, into } = 0,
87 Change { delete, inputs, current_of } = 1,
88 Open { cursor, inputs } = 2,
89 Fetch { cursor, into } = 3,
90 Close { cursor } = 4,
91 Commit = 5,
92 Rollback = 6,
93 Declaration = 7,
94 Unsupported(what) = 8,
95 Connect { what, location } = 9,
96 Prepare { name, source } = 10,
97 ExecuteImmediate { source } = 11,
98 Execute { name, inputs } = 12,
99 OpenPrepared { cursor, statement, inputs } = 13,
100});
101codec_struct!(HostPlace { var, member, ty, indicator } check host_place_valid);
102codec_struct!(Sqlca { fields } check sqlca_valid);
103codec_enum!(SqlcaField {
104 CaId = 0,
105 CaBc = 1,
106 Code = 2,
107 ErrMl = 3,
108 ErrMc = 4,
109 ErrP = 5,
110 State = 6,
111 ErrD(n) = 7,
112 Warn(n) = 8,
113});
114
115fn not_a_structure(ty: &HostType) -> Result<(), String> {
117 match ty {
118 HostType::Structure(_) => Err("a host structure where lowering gives its members".into()),
119 _ => Ok(()),
120 }
121}
122
123fn host_place_valid(place: &HostPlace) -> Result<(), String> {
124 place.ty.as_ref().map_or(Ok(()), not_a_structure)
125}
126
127fn sqlca_valid(sqlca: &Sqlca) -> Result<(), String> {
128 for (field, _, ty) in &sqlca.fields {
129 match *field {
130 SqlcaField::ErrD(n) if !(1..=6).contains(&n) => return Err(format!("SQLERRD({n}) is not an SQLCA field")),
131 SqlcaField::Warn(n) if n > 10 => return Err(format!("SQLWARN{n} is not an SQLCA field")),
132 _ => not_a_structure(ty)?,
133 }
134 }
135 Ok(())
136}
137
138pub(super) fn table_valid(table: &[SqlEntry], symbols: &[String]) -> Result<(), String> {
141 let symbol = |id: SymId| symbols.get(id as usize).ok_or_else(|| format!("symbol {id} of a table of {}", symbols.len()));
142 for (k, entry) in (1u32..).zip(table) {
143 if entry.ordinal != k {
144 return Err(format!("SQL entry {k} has ordinal {}", entry.ordinal));
145 }
146 let text = symbol(entry.text)?;
147 if entry.fingerprint != fingerprint(text) {
148 return Err(format!("SQL entry {k} has fingerprint {:08X}, not its text's {:08X}", entry.fingerprint, fingerprint(text)));
149 }
150 let held = match &entry.statement {
151 SqlStatement::Open { cursor, .. } | SqlStatement::OpenPrepared { cursor, .. } => text.starts_with(&format!("DECLARE {} CURSOR WITH HOLD FOR ", symbol(*cursor)?)),
152 _ => false,
153 };
154 if entry.with_hold != held {
155 return Err(format!("SQL entry {k} has WITH HOLD {} for its text", if entry.with_hold { "set" } else { "clear" }));
156 }
157 }
158 Ok(())
159}