nuno-faria commented on code in PR #19221:
URL: https://github.com/apache/datafusion/pull/19221#discussion_r2628395045


##########
datafusion/sql/src/unparser/ast.rs:
##########
@@ -140,7 +140,15 @@ impl Default for QueryBuilder {
 pub struct SelectBuilder {
     distinct: Option<ast::Distinct>,
     top: Option<ast::Top>,
-    projection: Vec<ast::SelectItem>,
+    /// Projection items for the SELECT clause.
+    ///
+    /// This field uses `Option` to distinguish between three distinct states:
+    /// - `None`: No projection has been set (not yet initialized)
+    /// - `Some(vec![])`: Empty projection explicitly set (generates `SELECT 
FROM ...` or `SELECT 1 FROM ...`)
+    /// - `Some(vec![...])`: Non-empty projection with specific 
columns/expressions
+    ///
+    /// Use `projection()` to set this field and `already_projected()` to 
check if it has been set.
+    projection: Option<Vec<ast::SelectItem>>,

Review Comment:
   For anyone else reviewing this: projection needs to be an `Option` to be 
able to distinguish between explicitly empty (`SELECT FROM`) and select all 
(`SELECT * FROM`).



##########
datafusion/sql/src/unparser/plan.rs:
##########
@@ -98,6 +98,16 @@ pub fn plan_to_sql(plan: &LogicalPlan) -> 
Result<ast::Statement> {
 }
 
 impl Unparser<'_> {
+    /// Generates appropriate projection expression for empty projection lists.
+    /// Returns an empty vec for dialects supporting empty select lists,
+    /// or a dummy literal `1` for other dialects.
+    fn empty_projection_fallback(&self) -> Vec<Expr> {
+        if self.dialect.supports_empty_select_list() {
+            Vec::new()
+        } else {
+            vec![Expr::Literal(ScalarValue::Int64(Some(1)), None)]
+        }
+    }

Review Comment:
   nit: Perhaps it's better to move this method to the end of Unparser, so 
`plan_to_sql` remains at the top.



##########
datafusion/sql/src/unparser/dialect.rs:
##########
@@ -218,6 +218,46 @@ pub trait Dialect: Send + Sync {
     fn timestamp_with_tz_to_string(&self, dt: DateTime<Tz>, _unit: TimeUnit) 
-> String {
         dt.to_string()
     }
+
+    /// Whether the dialect supports an empty select list such as `SELECT FROM 
table`.
+    ///
+    /// An empty select list returns rows without any column data, which is 
useful for:
+    /// - Counting rows: `SELECT FROM users WHERE active = true` (combined 
with `COUNT(*)`)
+    /// - Testing row existence without retrieving column data
+    /// - Performance optimization when only row counts or existence checks 
are needed
+    ///
+    /// # Supported Databases
+    ///
+    /// - **PostgreSQL**: Fully supported. Returns rows with zero columns.
+    /// - **DataFusion**: Supported natively.

Review Comment:
   nit: Since there isn't a DataFusion dialect (and the `DefaultDialect` 
returns false) it might be better to remove it from the documentation to avoid 
any confusion.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to