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