Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: relational literals with zero rows #4693

Merged
merged 1 commit into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions prqlc/prqlc/src/sql/gen_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,25 @@ fn translate_cte(cte: Cte, ctx: &mut Context) -> Result<(sql_ast::Cte, bool)> {
fn translate_relation_literal(data: RelationLiteral, ctx: &Context) -> Result<sql_ast::Query> {
// TODO: this could be made to use VALUES instead of SELECT UNION ALL SELECT
// I'm not sure about compatibility though.
// edit: probably not, because VALUES has no way of setting names of the columns
// Postgres will just name them column1, column2 as so on.
// Which means we can use VALUES, but only if this is not the top-level statement,
// where they really matter.

if data.rows.is_empty() {
return Ok(default_query(sql_ast::SetExpr::Select(Box::new(Select {
projection: data
.columns
.iter()
.map(|col_name| SelectItem::ExprWithAlias {
expr: sql_ast::Expr::Value(sql_ast::Value::Null),
alias: translate_ident_part(col_name.clone(), ctx),
})
.collect(),
selection: Some(sql_ast::Expr::Value(sql_ast::Value::Boolean(false))),
..default_select()
}))));
}

let mut selects = Vec::with_capacity(data.rows.len());

Expand All @@ -444,15 +463,6 @@ fn translate_relation_literal(data: RelationLiteral, ctx: &Context) -> Result<sq
selects.push(body)
}

if selects.is_empty() {
return Err(
Error::new_simple("No rows provided for `from_text`".to_string()).push_hint(
"add a newline, then a row of data following the column. If using \
the json format, ensure `data` isn't empty",
),
);
}

let mut body = selects.remove(0);
for select in selects {
body = SetExpr::SetOperation {
Expand Down
51 changes: 50 additions & 1 deletion prqlc/prqlc/tests/integration/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4194,7 +4194,7 @@ fn test_name_inference() {
}

#[test]
fn test_from_text() {
fn test_from_text_01() {
assert_snapshot!(compile(r#"
from_text format:csv """
a,b,c
Expand Down Expand Up @@ -4223,7 +4223,10 @@ a,b,c
table_0
"###
);
}

#[test]
fn test_from_text_02() {
assert_snapshot!(compile(r#"
from_text format:json '''
[{"a": 1, "b": "x", "c": false }, {"a": 4, "b": "y", "c": null }]
Expand All @@ -4250,7 +4253,10 @@ a,b,c
table_0
"###
);
}

#[test]
fn test_from_text_03() {
assert_snapshot!(compile(r#"
std.from_text format:json '''{
"columns": ["a", "b", "c"],
Expand Down Expand Up @@ -4283,6 +4289,49 @@ a,b,c
);
}

#[test]
fn test_from_text_04() {
assert_snapshot!(compile(r#"
std.from_text 'a,b'
"#).unwrap(),
@r###"
WITH table_0 AS (
SELECT
NULL AS a,
NULL AS b
WHERE
false
)
SELECT
a,
b
FROM
table_0
"###
);

assert_snapshot!(compile(r#"
std.from_text format:json '''{"columns": ["a", "b", "c"], "data": []}'''
"#).unwrap(),
@r###"
WITH table_0 AS (
SELECT
NULL AS a,
NULL AS b,
NULL AS c
WHERE
false
)
SELECT
a,
b,
c
FROM
table_0
"###
);
}

#[test]
fn test_header() {
// Test both target & version at the same time
Expand Down
Loading