#![cfg(feature = "std")]
use graphitesql::{Connection, Value};
fn setup() -> Connection {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE x(a, b)").unwrap();
c.execute("CREATE TABLE y(a, c)").unwrap();
c.execute("INSERT INTO x VALUES(1, 10)").unwrap();
c.execute("INSERT INTO y VALUES(2, 20)").unwrap();
c
}
#[test]
fn ambiguous_bare_reference_is_rejected() {
let c = setup();
assert!(c.query("SELECT a FROM x, y").is_err());
assert!(c.query("SELECT a FROM x JOIN y ON x.a = y.a").is_err());
assert!(c.query("SELECT 1 FROM x, y WHERE a = 1").is_err());
assert!(c.query("SELECT 1 FROM x, y ORDER BY a").is_err());
assert!(c.query("SELECT count(a) FROM x, y").is_err());
assert!(c.query("SELECT a FROM x, y GROUP BY a").is_err());
assert!(c
.query("SELECT b, c FROM x, y GROUP BY b, c HAVING a > 0")
.is_err());
}
#[test]
fn unaliased_self_join_is_ambiguous() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE z(a, b)").unwrap();
assert!(c.query("SELECT a FROM z, z").is_err());
assert!(c.query("SELECT z.a FROM z, z").is_err());
assert!(c.query("SELECT * FROM z, z").is_err());
assert!(c.query("SELECT * FROM z AS p, z AS q").is_ok());
assert!(c.query("SELECT p.a FROM z AS p, z AS q").is_ok());
assert!(c.query("SELECT a FROM z AS p, z AS q").is_err());
}
#[test]
fn coalesced_and_qualified_references_are_not_ambiguous() {
let c = setup();
assert_eq!(
c.query("SELECT a FROM x JOIN y USING(a)")
.unwrap()
.rows
.len(),
0 );
assert!(c.query("SELECT a FROM x NATURAL JOIN y").is_ok());
assert_eq!(
c.query("SELECT x.a FROM x, y ORDER BY x.a").unwrap().rows[0][0],
Value::Integer(1)
);
assert_eq!(
c.query("SELECT b FROM x, y").unwrap().rows[0][0],
Value::Integer(10)
);
}
#[test]
fn shared_name_with_distinct_qualifiers_over_a_join_is_fine() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE a(id, name)").unwrap();
c.execute("CREATE TABLE b(id, aid, val)").unwrap();
c.execute("INSERT INTO a VALUES(1, 'x'), (2, 'y')").unwrap();
c.execute("INSERT INTO b VALUES(10, 1, 100), (11, 2, 200)")
.unwrap();
assert!(c.query("SELECT * FROM a JOIN b ON a.id = b.aid").is_ok());
assert_eq!(
c.query("SELECT a.id, b.val FROM a JOIN b ON a.id = b.aid ORDER BY a.id")
.unwrap()
.rows
.len(),
2
);
assert!(c
.query("SELECT t1.id FROM a t1 JOIN a t2 ON t1.id = t2.id")
.is_ok());
}
#[test]
fn subquery_reference_to_ambiguous_outer_from_is_rejected() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE x(a, b)").unwrap();
c.execute("CREATE TABLE y(a, c)").unwrap();
c.execute("CREATE TABLE w(d, e)").unwrap();
assert!(c.query("SELECT (SELECT a) FROM x, y").is_err());
assert!(c.query("SELECT (SELECT a FROM w) FROM x, y").is_err());
assert!(c
.query("SELECT 1 FROM x, y WHERE EXISTS(SELECT 1 FROM w WHERE d = a)")
.is_err());
assert!(c
.query("SELECT 1 FROM x, y WHERE b IN (SELECT d FROM w WHERE e = a)")
.is_err());
assert!(c
.query("SELECT * FROM w WHERE d IN (SELECT a FROM x, y)")
.is_err());
}
#[test]
fn subquery_reference_that_binds_locally_or_uniquely_is_fine() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE x(a, b)").unwrap();
c.execute("CREATE TABLE y(a, c)").unwrap();
c.execute("CREATE TABLE wa(a, f)").unwrap();
assert!(c.query("SELECT (SELECT a FROM wa) FROM x, y").is_ok());
c.execute("CREATE TABLE emp(id, dept_id, sal)").unwrap();
c.execute("CREATE TABLE dept(id, dname)").unwrap();
assert!(c
.query("SELECT (SELECT dname FROM dept WHERE id = e.dept_id) FROM emp e")
.is_ok());
assert!(c
.query(
"SELECT sal FROM emp e WHERE sal > (SELECT avg(sal) FROM emp WHERE dept_id = e.dept_id)"
)
.is_ok());
}