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 Describe { name: S, descriptor: P, names: SqlNames },
45 PrepareInto { name: S, source: Vec<HostPlace<P>>, descriptor: P, names: SqlNames },
47 ExecuteDescriptor { name: S, descriptor: P },
48 OpenDescriptor { cursor: S, statement: S, descriptor: P },
49 FetchDescriptor { cursor: S, descriptor: P },
50 FetchRowset { cursor: S, rows: RowCount<P>, into: Vec<HostArray<P>>, enabled: bool },
53 InsertRows { inputs: Vec<HostArray<P>>, rows: RowCount<P>, atomic: bool },
56 Call { procedure: S, args: Vec<HostPlace<P>> },
59 Declaration,
61 Unsupported(S),
63 Connect { what: S, location: Vec<HostPlace<P>> },
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub enum SqlNames {
71 Names,
72 Labels,
73 Any,
74}
75
76#[derive(Clone, Debug, PartialEq, Eq)]
79pub struct HostPlace<P = PlaceId> {
80 pub var: P,
81 pub member: Option<(u32, u32)>,
82 pub ty: Result<HostType, AbendId>,
84 pub indicator: Option<(P, u32)>,
85}
86
87#[derive(Clone, Debug, PartialEq, Eq)]
91pub struct HostArray<P = PlaceId> {
92 pub place: HostPlace<P>,
93 pub array: Option<Dimension>,
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq)]
98pub struct Dimension {
99 pub stride: u32,
100 pub count: u32,
101 pub indicator_stride: u32,
102}
103
104#[derive(Clone, Debug, PartialEq, Eq)]
106pub enum RowCount<P = PlaceId> {
107 Implicit,
108 Constant(u32),
109 Host(HostPlace<P>),
110}
111
112#[derive(Clone, Debug, Default, PartialEq, Eq)]
114pub struct Sqlca<P = PlaceId> {
115 pub fields: Vec<(SqlcaField, P, HostType)>,
116}
117
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119pub enum SqlcaField {
120 CaId,
121 CaBc,
122 Code,
123 ErrMl,
124 ErrMc,
125 ErrP,
126 State,
127 ErrD(u8),
129 Warn(u8),
131}
132
133codec_struct!(SqlEntry { ordinal, verb, statement, text, fingerprint, with_hold });
134codec_enum!(SqlStatement {
135 Query { inputs, into } = 0,
136 Change { delete, inputs, current_of } = 1,
137 Open { cursor, inputs } = 2,
138 Fetch { cursor, into } = 3,
139 Close { cursor } = 4,
140 Commit = 5,
141 Rollback = 6,
142 Declaration = 7,
143 Unsupported(what) = 8,
144 Connect { what, location } = 9,
145 Prepare { name, source } = 10,
146 ExecuteImmediate { source } = 11,
147 Execute { name, inputs } = 12,
148 OpenPrepared { cursor, statement, inputs } = 13,
149 Describe { name, descriptor, names } = 14,
150 PrepareInto { name, source, descriptor, names } = 15,
151 ExecuteDescriptor { name, descriptor } = 16,
152 OpenDescriptor { cursor, statement, descriptor } = 17,
153 FetchDescriptor { cursor, descriptor } = 18,
154 FetchRowset { cursor, rows, into, enabled } = 19,
155 InsertRows { inputs, rows, atomic } = 20,
156 Call { procedure, args } = 21,
157});
158codec_enum!(SqlNames {
159 Names = 0,
160 Labels = 1,
161 Any = 2,
162});
163codec_struct!(HostPlace { var, member, ty, indicator } check host_place_valid);
164codec_struct!(HostArray { place, array });
165codec_struct!(Dimension { stride, count, indicator_stride });
166codec_enum!(RowCount { Implicit = 0, Constant(n) = 1, Host(place) = 2 });
167codec_struct!(Sqlca { fields } check sqlca_valid);
168codec_enum!(SqlcaField {
169 CaId = 0,
170 CaBc = 1,
171 Code = 2,
172 ErrMl = 3,
173 ErrMc = 4,
174 ErrP = 5,
175 State = 6,
176 ErrD(n) = 7,
177 Warn(n) = 8,
178});
179
180fn not_a_structure(ty: &HostType) -> Result<(), String> {
182 match ty {
183 HostType::Structure(_) => Err("a host structure where lowering gives its members".into()),
184 _ => Ok(()),
185 }
186}
187
188fn host_place_valid(place: &HostPlace) -> Result<(), String> {
189 place.ty.as_ref().map_or(Ok(()), not_a_structure)
190}
191
192fn sqlca_valid(sqlca: &Sqlca) -> Result<(), String> {
193 for (field, _, ty) in &sqlca.fields {
194 match *field {
195 SqlcaField::ErrD(n) if !(1..=6).contains(&n) => return Err(format!("SQLERRD({n}) is not an SQLCA field")),
196 SqlcaField::Warn(n) if n > 10 => return Err(format!("SQLWARN{n} is not an SQLCA field")),
197 _ => not_a_structure(ty)?,
198 }
199 }
200 Ok(())
201}
202
203pub(super) fn table_valid(table: &[SqlEntry], symbols: &[String]) -> Result<(), String> {
206 let symbol = |id: SymId| symbols.get(id as usize).ok_or_else(|| format!("symbol {id} of a table of {}", symbols.len()));
207 for (k, entry) in (1u32..).zip(table) {
208 if entry.ordinal != k {
209 return Err(format!("SQL entry {k} has ordinal {}", entry.ordinal));
210 }
211 let text = symbol(entry.text)?;
212 if entry.fingerprint != fingerprint(text) {
213 return Err(format!("SQL entry {k} has fingerprint {:08X}, not its text's {:08X}", entry.fingerprint, fingerprint(text)));
214 }
215 let held = match &entry.statement {
216 SqlStatement::Open { cursor, .. } | SqlStatement::OpenPrepared { cursor, .. } | SqlStatement::OpenDescriptor { cursor, .. } => text.starts_with(&format!("DECLARE {} CURSOR WITH HOLD FOR ", symbol(*cursor)?)),
217 _ => false,
218 };
219 if entry.with_hold != held {
220 return Err(format!("SQL entry {k} has WITH HOLD {} for its text", if entry.with_hold { "set" } else { "clear" }));
221 }
222 }
223 Ok(())
224}