use spg_engine::{Engine, QueryResult};
fn vals(e: &mut Engine, sql: &str) -> Vec<String> {
match e.execute(sql).unwrap_or_else(|err| panic!("{sql}: {err}")) {
QueryResult::Rows { rows, .. } => rows
.iter()
.map(|r| {
r.values
.iter()
.map(spg_engine::eval::value_to_text)
.collect::<Vec<_>>()
.join("|")
})
.collect(),
other => panic!("{sql}: {other:?}"),
}
}
fn seed() -> Engine {
let mut e = Engine::new();
e.execute(
"CREATE TABLE b0 (i INT, ia INT[], ta TEXT[], na NUMERIC[], ba BOOL[], \
da DATE[], bga BIGINT[], sa SMALLINT[], fa FLOAT8[], ua UUID[])",
)
.unwrap();
e.execute(
"INSERT INTO b0 VALUES (1, ARRAY[1,2], ARRAY['x','y'], ARRAY[1.5], ARRAY[true], \
ARRAY[DATE '2020-01-02'], ARRAY[9223372036854775807], ARRAY[32767::SMALLINT], \
ARRAY[1.5::FLOAT8], ARRAY['00000000-0000-0000-0000-000000000001'::UUID])",
)
.unwrap();
e.execute("INSERT INTO b0 VALUES (2, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)")
.unwrap();
e.execute(
"INSERT INTO b0 VALUES (3, ARRAY[]::INT[], ARRAY[]::TEXT[], NULL,NULL,NULL,NULL,NULL,NULL,NULL)",
)
.unwrap();
e.execute(
"INSERT INTO b0 VALUES (4, ARRAY[1,NULL,2], ARRAY['a b','c,d',NULL], \
NULL,NULL,NULL,NULL,NULL,NULL,NULL)",
)
.unwrap();
e
}
#[test]
fn round621_insert_select_carries_arrays() {
let mut e = seed();
e.execute("CREATE TABLE b1 (LIKE b0)").unwrap();
e.execute("INSERT INTO b1 SELECT * FROM b0").unwrap();
assert_eq!(
vals(&mut e, "SELECT i, ia, ta, na, ba FROM b1 ORDER BY i"),
vec![
"1|{1,2}|{x,y}|{1.5}|{t}",
"2|NULL|NULL|NULL|NULL",
"3|{}|{}|NULL|NULL",
r#"4|{1,NULL,2}|{"a b","c,d",NULL}|NULL|NULL"#,
],
"a NULL array, an EMPTY array, a NULL ELEMENT, and text that has to \
stay quoted — all four are separate ways for a rebuild to go wrong"
);
assert_eq!(
vals(&mut e, "SELECT i, da, bga, sa, fa, ua FROM b1 WHERE i = 1"),
vec![
"1|{2020-01-02}|{9223372036854775807}|{32767}|{1.5}|\
{00000000-0000-0000-0000-000000000001}"
],
"and the element types that materialise through a cast of their own"
);
}
#[test]
fn round621_the_other_spellings() {
let mut e = seed();
e.execute("CREATE TABLE b2 (i INT, ia INT[])").unwrap();
e.execute("INSERT INTO b2 (i, ia) SELECT i, ia FROM b0")
.unwrap();
assert_eq!(
vals(&mut e, "SELECT i, ia FROM b2 ORDER BY i"),
vec!["1|{1,2}", "2|NULL", "3|{}", "4|{1,NULL,2}"],
"a named column list"
);
e.execute("CREATE TABLE b3 AS SELECT i, ta FROM b0")
.unwrap();
assert_eq!(
vals(&mut e, "SELECT i, ta FROM b3 ORDER BY i"),
vec!["1|{x,y}", "2|NULL", "3|{}", r#"4|{"a b","c,d",NULL}"#],
"CREATE TABLE … AS SELECT, which could not carry one either"
);
e.execute("CREATE TABLE b4 (i INT, ia INT[])").unwrap();
e.execute("INSERT INTO b4 (i, ia) SELECT i, ARRAY[i, i*2] FROM b0")
.unwrap();
assert_eq!(
vals(&mut e, "SELECT i, ia FROM b4 ORDER BY i"),
vec!["1|{1,2}", "2|{2,4}", "3|{3,6}", "4|{4,8}"],
"an array COMPUTED in the inner select"
);
e.execute("CREATE TABLE b5 (i INT, ia INT[])").unwrap();
e.execute("INSERT INTO b5 (i, ia) SELECT i, ia FROM b0 WHERE ia IS NOT NULL")
.unwrap();
assert_eq!(
vals(&mut e, "SELECT i FROM b5 ORDER BY i"),
vec!["1", "3", "4"]
);
e.execute("CREATE TABLE b6 (i INT, ia INT[])").unwrap();
e.execute("INSERT INTO b6 (i, ia) SELECT i, ia::INT[] FROM b0")
.unwrap();
assert_eq!(
vals(&mut e, "SELECT count(*) FROM b6"),
vec!["4"],
"the explicit CAST the old error told the caller to add, which did \
not help either"
);
}
#[test]
fn round621_what_lands_is_an_array() {
let mut e = seed();
e.execute("CREATE TABLE b7 (i INT, ia INT[])").unwrap();
e.execute("INSERT INTO b7 (i, ia) SELECT i, ia FROM b0")
.unwrap();
assert_eq!(
vals(
&mut e,
"SELECT i, array_length(ia,1), ia[1] FROM b7 ORDER BY i"
),
vec!["1|2|1", "2|NULL|NULL", "3|NULL|NULL", "4|3|1"],
"subscript and length work on it, so it is an array"
);
assert_eq!(
vals(&mut e, "SELECT count(*) FROM b7 WHERE ia @> ARRAY[1]"),
vec!["2"],
"and the containment operator finds it"
);
assert_eq!(
vals(&mut e, "SELECT pg_typeof(ia) FROM b7 WHERE i = 1"),
vec!["integer[]"]
);
}