Skip to content

Commit

Permalink
Merge pull request #268 from Qrlew/bug_joins
Browse files Browse the repository at this point in the history
Preserve columns names when SELECT * and JOIN
  • Loading branch information
ngrislain authored Mar 19, 2024
2 parents 0d95e82 + c3f307f commit aba5b5e
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 157 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [0.9.15] - 2024-02-20
### Changed
- removing the coalesce of the privacy unit with since it looses the UNIQUE property and changing the JOIN to left instead of INNER after the clipping.
- SELECT * with JOINs preserve the column names when there is no ambiguity [#268](https://github.com/Qrlew/qrlew/pull/268)
- removing the coalesce of the privacy unit with since it looses the UNIQUE property and changing the JOIN to left instead of INNER after the clipping. [#272](https://github.com/Qrlew/qrlew/pull/272)

## [0.9.14] - 2024-01-30
### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
authors = ["Nicolas Grislain <ng@sarus.tech>"]
name = "qrlew"
version = "0.9.14"
version = "0.9.15"
edition = "2021"
description = "Sarus Qrlew Engine"
documentation = "https://docs.rs/qrlew"
Expand Down
40 changes: 10 additions & 30 deletions src/dialect_translation/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,7 @@ mod tests {

use super::*;
use crate::{
builder::{Ready, With},
data_type::{DataType, Value as _},
display::Dot,
expr::Expr,
namer,
relation::{schema::Schema, Relation, TableBuilder},
sql::{parse, relation::QueryWithRelations},
builder::{Ready, With}, data_type::{DataType, Value as _}, display::Dot, expr::Expr, io::{postgresql, Database as _}, namer, relation::{schema::Schema, Relation, TableBuilder}, sql::{parse, relation::QueryWithRelations}
};
use std::sync::Arc;

Expand Down Expand Up @@ -154,36 +148,22 @@ mod tests {

#[test]
fn test_table_special() -> Result<()> {
let table: Relation = TableBuilder::new()
.path(["MY SPECIAL TABLE"])
.name("my_table")
.size(100)
.schema(
Schema::empty()
.with(("Id", DataType::integer_interval(0, 1000)))
.with(("Na.Me", DataType::text()))
.with(("inc&ome", DataType::float_interval(100.0, 200000.0)))
.with(("normal_col", DataType::text())),
)
.build();
let relations = Hierarchy::from([(["schema", "MY SPECIAL TABLE"], Arc::new(table))]);
let mut database = postgresql::test_database();
let relations = database.relations();
let query_str = r#"SELECT "Id", NORMAL_COL, "Na.Me" FROM "MY SPECIAL TABLE" ORDER BY "Id" "#;
let translator = PostgreSqlTranslator;
let query = parse_with_dialect(query_str, translator.dialect())?;
let query_with_relation = QueryWithRelations::new(&query, &relations);
let relation = Relation::try_from((query_with_relation, translator))?;
println!("\n {} \n", relation);
let rel_with_traslator = RelationWithTranslator(&relation, translator);
let retranslated = ast::Query::from(rel_with_traslator);
print!("{}", retranslated);
let translated = r#"
WITH "map_mou5" ("Id","normal_col","Na.Me") AS (
SELECT "Id" AS "Id", "normal_col" AS "normal_col", "Na.Me" AS "Na.Me" FROM "MY SPECIAL TABLE"
), "map_0swv"("Id","normal_col","Na.Me") AS (
SELECT "Id" AS "Id", "normal_col" AS "normal_col", "Na.Me" AS "Na.Me" FROM "map_mou5" ORDER BY "Id" ASC
) SELECT * FROM "map_0swv"
"#;
assert_same_query_str(&retranslated.to_string(), translated);
let translated = ast::Query::from(rel_with_traslator);
print!("{}", translated);
_ = database
.query(translated.to_string().as_str())
.unwrap()
.iter()
.map(ToString::to_string);
Ok(())
}
}
42 changes: 28 additions & 14 deletions src/relation/rewriting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,38 +202,52 @@ impl Join {
self
}

/// Replace the duplicates fields specified in `columns` by their coalesce expression
/// Its mimicks teh behaviour of USING in SQL
/// To mimic the behavior of USING(col) and NATURAL JOIN in SQL we create
/// a map where join columns identified by `vec` are coalesced.
/// vec: vector of string identifying input columns present in both _LEFT_
/// and _RIGHT_ relation of the join.
/// columns: is the Hierarchy mapping input names in the JOIN to name field
///
/// It returns a:
/// - Map build on top the Join with coalesced column along with
/// the other fields of the join and
/// - coalesced columns mapping (name in join -> name in map)
pub fn remove_duplicates_and_coalesce(
self,
vec: Vec<String>,
columns: &Hierarchy<Identifier>,
) -> Relation {
let fields = self
) -> (Relation, Hierarchy<Identifier>) {
let mut coalesced_cols: Vec<(Identifier, Identifier)> = vec![];
let coalesced = self
.field_inputs()
.filter_map(|(name, id)| {
let col = id.as_ref().last().unwrap();
if id.as_ref().first().unwrap().as_str() == LEFT_INPUT_NAME && vec.contains(col) {
.filter_map(|(_, input_id)| {
let col = input_id.as_ref().last().unwrap();
if input_id.as_ref().first().unwrap().as_str() == LEFT_INPUT_NAME && vec.contains(col) {
let left_col = columns[[LEFT_INPUT_NAME, col]].as_ref().last().unwrap();
let right_col = columns[[RIGHT_INPUT_NAME, col]].as_ref().last().unwrap();
coalesced_cols.push((left_col.as_str().into(), col[..].into()));
coalesced_cols.push((right_col.as_str().into(), col[..].into()));
Some((
name,
col.clone(),
Expr::coalesce(
Expr::col(columns[[LEFT_INPUT_NAME, col]].as_ref().last().unwrap()),
Expr::col(columns[[RIGHT_INPUT_NAME, col]].as_ref().last().unwrap()),
Expr::col(left_col),
Expr::col(right_col),
),
))
} else {
None
}
})
});
let coalesced_with_others = coalesced
.chain(self.field_inputs().filter_map(|(name, id)| {
let col = id.as_ref().last().unwrap();
(!vec.contains(col)).then_some((name.clone(), Expr::col(name)))
}))
.collect::<Vec<_>>();
Relation::map()
(Relation::map()
.input(Relation::from(self))
.with_iter(fields)
.build()
.with_iter(coalesced_with_others)
.build(), coalesced_cols.into_iter().collect())
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/sql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ mod tests {
use itertools::Itertools;
use sqlparser::dialect::BigQueryDialect;


#[test]
fn test_display() {
let database = postgresql::test_database();
Expand All @@ -132,12 +133,12 @@ mod tests {
t2 AS (SELECT * FROM table_2)
SELECT max(a), sum(d) FROM t1 INNER JOIN t2 ON t1.d = t2.x CROSS JOIN table_2 GROUP BY t2.y, t1.a",
"
WITH t1 AS (SELECT a,d FROM table_1),
WITH t1 AS (SELECT a, d FROM table_1),
t2 AS (SELECT * FROM table_2)
SELECT * FROM t1 INNER JOIN t2 ON t1.d = t2.x INNER JOIN table_2 ON t1.d=table_2.x ORDER BY t1.a LIMIT 10",
] {
let relation = Relation::try_from(parse(query).unwrap().with(&database.relations())).unwrap();
relation.display_dot();
relation.display_dot().unwrap();
}
}

Expand Down
Loading

0 comments on commit aba5b5e

Please sign in to comment.