Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

Unparser turns NULL list literals into `[]` and fails on NULL struct/map literals

Ouverte Adaptée aux débutants
#26,316 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
72/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
rust, sql
Domaine
databases

Piste de recherche

Commence dans Unparser::scalar_to_sql dans datafusion/sql/src/unparser/expr.rs. Les branches List (environ lignes 1450-1454) rendent les valeurs enfants sans vérifier la présence de null, et les branches Struct, Map et Union (environ lignes 1579-1581) renvoient not_impl_err! même pour les null. Reproduis avec les deux requêtes CASE de l'issue, puis vérifie que les null typés comme Int32(None) sont déjà convertis en NULL. Terminé quand les littéraux NULL de types imbriqués sont convertis en NULL et que les tests existants de l'unparser datafusion-sql passent toujours.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

bug help wanted unparser
Describe the bug

The SQL unparser mishandles NULL literals of nested types:

  • A NULL list literal unparses as [], so the generated SQL returns an empty array where the plan returns NULL, with no error.
  • A NULL struct, map, or union literal fails with NotImplemented("Unsupported scalar: ...").

Optimized plans contain these literals whenever type coercion casts a NULL to a nested type and constant folding turns the cast into a literal, e.g. CASE WHEN ... THEN NULL ELSE list_col END or ... UNION ALL SELECT NULL.

The cause is in Unparser::scalar_to_sql. The list arms render the scalar's child values without checking whether the list itself is null (unparser/expr.rs#L1450-L1454), and the Struct/Map/Union arms return not_impl_err! even for nulls (unparser/expr.rs#L1579-L1581). Every other typed null, such as Int32(None) or DurationSecond(None), unparses as NULL.

To Reproduce
use datafusion::error::Result;
use datafusion::prelude::*;
use datafusion::sql::unparser::plan_to_sql;

#[tokio::main]
async fn main() -> Result<()> {
    let ctx = SessionContext::new();
    ctx.sql("CREATE TABLE t AS SELECT 1 AS a, [1, 2] AS l, named_struct('x', 1) AS s")
        .await?;
    for sql in [
        "SELECT CASE WHEN a > 0 THEN NULL ELSE l END AS c FROM t",
        "SELECT CASE WHEN a > 0 THEN NULL ELSE s END AS c FROM t",
    ] {
        let plan = ctx.sql(sql).await?.into_optimized_plan()?;
        println!("{:?}", plan_to_sql(&plan).map(|s| s.to_string()));
    }
    Ok(())
}

Output:

Ok("SELECT CASE WHEN (t.a > 0) THEN [] ELSE t.l END AS c FROM t")
Err(NotImplemented("Unsupported scalar: Struct({x:})"))

Running the first unparsed query returns [] where the original returns NULL. SELECT l FROM t UNION ALL SELECT NULL FROM t similarly unparses to ... UNION ALL SELECT [] AS l FROM t. Map columns fail the same way as struct columns.

Expected behavior

NULL nested-type literals unparse as NULL, like other typed nulls, e.g. CASE WHEN (t.a > 0) THEN NULL ELSE t.l END.

A guard arm at the top of scalar_to_sql is enough:

ScalarValue::List(_)
| ScalarValue::LargeList(_)
| ScalarValue::FixedSizeList(_)
| ScalarValue::ListView(_)
| ScalarValue::LargeListView(_)
| ScalarValue::Struct(_)
| ScalarValue::Map(_)
| ScalarValue::Union(..)
    if v.is_null() =>
{
    Ok(ast::Expr::value(ast::Value::Null))
}

With this arm, the queries above, the UNION ALL case, and the map case all unparse to SQL that returns the same results as the original query, and the existing datafusion-sql tests still pass.

Additional context
  • Non-null struct and map literals, such as a constant-folded named_struct('x', 1), also fail with Unsupported scalar. Rendering those needs dialect-specific syntax, so they are out of scope here.
  • Once #26311 merges, CASE WHEN a > 0 THEN s ELSE NULL END fails the same way. Until then the unparser drops the failing ELSE, which happens to give the same result for ELSE NULL.
  • Line references are pinned to commit 0d79252f61bd.
Langage dominant
Rust
Étoiles
9.5k
Forks
2.5k
Merge moyen
4 j 12 h
PR mergées (30 j)
306

Préparer son environnement

Ouvrir dans Codespaces

Lance le conteneur de développement du projet dans votre navigateur, avec votre propre compte GitHub.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de apache/datafusion

Toutes les issues de apache/datafusion

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.