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