Skip to main content

ironwork_compile/
sql.rs

1//! The host type of a declared item, which EXEC SQL binds by: what `rt::sql` needs from the layout.
2
3use crate::layout::Layout;
4use rt::lir::Dimension;
5use rt::sql::HostType;
6use rt::storage::Kind;
7use zarch::hfp::Precision;
8
9/// The host type of layout item `item`, or why it cannot be a host variable.
10pub fn host_type(layout: &Layout, item: usize) -> Result<HostType, String> {
11    let it = &layout.items[item];
12    let name = it.name.as_deref().unwrap_or("FILLER");
13    Ok(match it.kind {
14        Kind::Binary { scale: 0, signed, .. } => match it.size {
15            2 => HostType::SmallInt { signed },
16            4 => HostType::Integer { signed },
17            8 => HostType::BigInt { signed },
18            n => return Err(format!("{name}: a binary item of {n} bytes has no SQL type")),
19        },
20        Kind::Binary { .. } => return Err(format!("{name}: a binary item with decimal places has no SQL type")),
21        Kind::Packed { digits, scale, signed } if digits <= 31 => HostType::Decimal { digits, scale, signed },
22        Kind::Zoned { digits, scale, signed, sign } if digits <= 31 => HostType::Zoned { digits, scale, signed, sign },
23        Kind::Packed { .. } | Kind::Zoned { .. } => return Err(format!("{name}: more than 31 digits has no SQL type")),
24        Kind::Float(Precision::Short) => HostType::Real,
25        Kind::Float(Precision::Long) => HostType::Double,
26        Kind::Alnum { .. } => HostType::Char(it.size),
27        Kind::Dbcs { edit: None, .. } => HostType::Graphic(it.size / 2),
28        Kind::Group => structure(layout, item, name)?,
29        _ => return Err(format!("{name}: this USAGE or PICTURE has no SQL type")),
30    })
31}
32
33/// How a multiple-row statement takes layout item `var`, named with or without subscripts, and its
34/// indicator: a host-variable array, an item of one OCCURS named without subscripts, with its
35/// dimension; None for one host variable; or why it is neither (Db2 13 for z/OS, Host-variable
36/// arrays in COBOL).
37pub fn host_array(layout: &Layout, var: usize, subscripted: bool, indicator: Option<(usize, bool)>) -> Result<Option<Dimension>, String> {
38    let it = &layout.items[var];
39    let name = it.name.as_deref().unwrap_or("FILLER");
40    match it.dims.len() {
41        _ if subscripted => return Ok(None),
42        0 => return Ok(None),
43        1 => {}
44        _ => return Err(format!("{name} is a table of more than one dimension, which no host-variable array is")),
45    }
46    if matches!(host_type(layout, var), Ok(HostType::Structure(_))) {
47        return Err(format!("{name} is a host-structure array, which Db2 for z/OS does not take in COBOL"));
48    }
49    let (stride, count) = it.dims[0];
50    match indicator {
51        None => Ok(Some(Dimension { stride, count, indicator_stride: 0 })),
52        Some((i, false)) if layout.items[i].dims.len() == 1 => {
53            let (indicator_stride, indicators) = layout.items[i].dims[0];
54            Ok(Some(Dimension { stride, count: count.min(indicators), indicator_stride }))
55        }
56        Some(_) => Err(format!("{name}'s indicator is not an indicator array, as a host-variable array's must be")),
57    }
58}
59
60/// A group is VARCHAR when it is a 49-level length halfword and a 49-level text, and otherwise a
61/// host structure of its members.
62fn structure(layout: &Layout, item: usize, name: &str) -> Result<HostType, String> {
63    let members: Vec<usize> = layout.items[item].children.iter().copied().filter(|&c| layout.items[c].redefines.is_none()).collect();
64    if let [length, text] = members[..] {
65        let (l, t) = (&layout.items[length], &layout.items[text]);
66        if l.level == 49 && t.level == 49 && l.size == 2 && matches!(l.kind, Kind::Binary { scale: 0, .. }) {
67            match t.kind {
68                Kind::Alnum { .. } => return Ok(HostType::VarChar(t.size)),
69                Kind::Dbcs { edit: None, .. } => return Ok(HostType::VarGraphic(t.size / 2)),
70                _ => {}
71            }
72        }
73    }
74    let mut out = Vec::new();
75    for m in members {
76        if layout.items[m].table {
77            return Err(format!("{name}: a host structure holding a table"));
78        }
79        match host_type(layout, m)? {
80            HostType::Structure(_) => return Err(format!("{name}: a host structure nested in another")),
81            t => out.push((m, t)),
82        }
83    }
84    if out.is_empty() {
85        return Err(format!("{name}: a group with no members"));
86    }
87    Ok(HostType::Structure(out))
88}