You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@datafusion.apache.org by "alexander-beedie (via GitHub)" <gi...@apache.org> on 2026/01/08 14:22:13 UTC
[PR] Fix identifier parsing not breaking on the pipe operator [datafusion-sqlparser-rs]
alexander-beedie opened a new pull request, #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156
Fixes a bug in Pipe SQL parsing with identifiers followed by the `|>` operator; `parse_identifiers` needed to break on `Token::VerticalBarRightAngleBracket` as well, otherwise it continues to consume the following tokens as `Ident`.
## Example
```sql
FROM t |> DROP c |> RENAME a AS x
```
Without the fix, the query after the "FROM" section gets incorrectly parsed as:
```rust
Drop { columns: [
Ident { value: "c", ... },
Ident { value: "RENAME", ... },
Ident { value: "a", ... },
Ident { value: "AS", ... },
Ident { value: "x", ... }]
}
```
After the fix the `|>`-separated sections are parsed correctly:
```
Drop { columns: [Ident { value: "c" }] }
Rename { mappings: [
IdentWithAlias { ident: Ident { value: "a" }, alias: Ident { value: "x" } }]
}
```
## Also
Updated the pipe operator tests with some new coverage for the above, and a helper that additionally validates queries that start "FROM tbl" with the pipe operator (which was missing).
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "iffyio (via GitHub)" <gi...@apache.org>.
iffyio commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2716270817
##########
tests/sqlparser_common.rs:
##########
@@ -16157,302 +16157,411 @@ fn parse_set_names() {
#[test]
fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
+ // Helper for testing pipe operators
+ struct PipeTest<'a> {
+ dialects: &'a TestedDialects,
+ from_first: bool,
+ }
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
+ impl PipeTest<'_> {
+ fn query(&self, table: &str, pipe_ops: &str) -> String {
+ if self.from_first {
+ format!("FROM {table} |> {pipe_ops}")
+ } else {
+ format!("SELECT * FROM {table} |> {pipe_ops}")
+ }
+ }
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
+ fn pipe(&self, table: &str, pipe_ops: &str) {
+ self.dialects.verified_stmt(&self.query(table, pipe_ops));
+ }
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
+ fn pipe_canonical(&self, table: &str, input: &str, canonical: &str) {
+ self.dialects.verified_query_with_canonical(
+ &self.query(table, input),
+ &self.query(table, canonical),
+ );
+ }
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
+ fn pipe_implicit_alias(&self, table: &str, expr: &str, alias: &str) {
+ // Test implicit alias syntax is canonicalized to explicit AS
+ // e.g., "SELECT id user_id" -> "SELECT id AS user_id"
+ self.dialects.verified_query_with_canonical(
+ &self.query(table, &format!("{expr} {alias}")),
+ &self.query(table, &format!("{expr} AS {alias}")),
+ );
+ }
+ }
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
+ // Test pipe operators with two dialect configurations:
+ // 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+ // 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+ let from_first_dialects =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first_dialects =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
+ // Run tests for both dialect configurations
+ for (dialects, from_first) in [
+ (&from_first_dialects, true),
+ (&select_first_dialects, false),
+ ] {
+ let t = PipeTest {
+ dialects,
+ from_first,
+ };
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
+ // 'select' pipe operator
Review Comment:
if its possible can we use the previous format of explicitly writing out the test cases and expected results? I imagine that might be more verbose but its useful readability wise to know the cases that are being covered and what the tests do at a glance
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "iffyio (via GitHub)" <gi...@apache.org>.
iffyio commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2726959379
##########
tests/sqlparser_common.rs:
##########
@@ -16200,304 +16198,702 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
-#[test]
-fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
-
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
-
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
-
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
-
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
-
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
-
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
-
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // union pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT BY NAME (SELECT * FROM admins)");
-
- // union pipe operator with BY NAME and multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator (BigQuery requires DISTINCT modifier for INTERSECT)
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins)");
-
- // intersect pipe operator with BY NAME modifier
- dialects
- .verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // intersect pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // except pipe operator (BigQuery requires DISTINCT modifier for EXCEPT)
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins)");
-
- // except pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // except pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // except pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // call pipe operator
- dialects.verified_stmt("SELECT * FROM users |> CALL my_function()");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5, 'test')");
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL namespace.function_name(col1, col2, 'literal')",
- );
-
- // call pipe operator with complex arguments
- dialects.verified_stmt("SELECT * FROM users |> CALL transform_data(col1 + col2)");
- dialects.verified_stmt("SELECT * FROM users |> CALL analyze_data('param1', 100, true)");
-
- // call pipe operator with aliases
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) AS al");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5) AS result_table");
- dialects.verified_stmt("SELECT * FROM users |> CALL namespace.func() AS my_alias");
-
- // multiple call pipe operators in sequence
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) |> CALL tvf2(arg2, arg3)");
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL transform(col1) |> CALL validate() |> CALL process(param)",
- );
-
- // multiple call pipe operators with aliases
- dialects.verified_stmt(
- "SELECT * FROM input_table |> CALL tvf1(arg1) AS step1 |> CALL tvf2(arg2) AS step2",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean_data |> CALL analyze(mode) AS results",
- );
-
- // call pipe operators mixed with other pipe operators
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL transform() |> WHERE status = 'active' |> CALL process(param)",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean |> SELECT col1, col2 |> CALL validate()",
- );
-
- // pivot pipe operator
- dialects.verified_stmt(
- "SELECT * FROM monthly_sales |> PIVOT(SUM(amount) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))",
- );
- dialects.verified_stmt("SELECT * FROM sales_data |> PIVOT(AVG(revenue) FOR region IN ('North', 'South', 'East', 'West'))");
-
- // pivot pipe operator with multiple aggregate functions
- dialects.verified_stmt("SELECT * FROM data |> PIVOT(SUM(sales) AS total_sales, COUNT(*) AS num_transactions FOR month IN ('Jan', 'Feb', 'Mar'))");
-
- // pivot pipe operator with compound column names
- dialects.verified_stmt("SELECT * FROM sales |> PIVOT(SUM(amount) FOR product.category IN ('Electronics', 'Clothing'))");
+/// Returns dialect configurations for pipe operator tests:
+/// 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+/// 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+fn pipe_dialects() -> [(TestedDialects, bool); 2] {
+ let from_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
+ [(from_first, true), (select_first, false)]
+}
+
+/// Macro to test pipe operator parsing with explicit input and canonical output.
+/// Usage: `test_pipe!(ctx, input = "...", canonical = "...")`
+macro_rules! test_pipe {
+ ($ctx:expr, input = $input:expr, canonical = $canonical:expr $(,)?) => {{
+ let (ref dialects, from_first) = $ctx;
+ let prefix = if from_first {
+ "FROM tbl"
+ } else {
+ "SELECT * FROM tbl"
+ };
+ dialects.verified_query_with_canonical(
+ &format!("{prefix} |> {}", $input),
+ &format!("{prefix} |> {}", $canonical),
+ );
+ }};
+}
- // pivot pipe operator mixed with other pipe operators
- dialects.verified_stmt("SELECT * FROM sales_data |> WHERE year = 2023 |> PIVOT(SUM(revenue) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))");
+#[test]
+fn parse_pipe_operator_as() {
+ for dialect in pipe_dialects() {
+ test_pipe!(dialect, input = "AS new_users", canonical = "AS new_users");
+ }
Review Comment:
can we drop the test_pipe macro entirely and write the test cases explicitly like `dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");`. And likely we should drop the `pipe_dialects()` method and construct the dialects explicitly too. For similar reason mentioned previously in that its not obvious without reading a bit of custom code to figure out what the tests are doing and I don't think its worth it in this case.
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#issuecomment-3789180530
Rebased / addressed test formatπ
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2737878332
##########
tests/sqlparser_common.rs:
##########
@@ -16200,304 +16198,702 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
-#[test]
-fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
-
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
-
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
-
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
-
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
-
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
-
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
-
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // union pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT BY NAME (SELECT * FROM admins)");
-
- // union pipe operator with BY NAME and multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator (BigQuery requires DISTINCT modifier for INTERSECT)
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins)");
-
- // intersect pipe operator with BY NAME modifier
- dialects
- .verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // intersect pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // except pipe operator (BigQuery requires DISTINCT modifier for EXCEPT)
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins)");
-
- // except pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // except pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // except pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // call pipe operator
- dialects.verified_stmt("SELECT * FROM users |> CALL my_function()");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5, 'test')");
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL namespace.function_name(col1, col2, 'literal')",
- );
-
- // call pipe operator with complex arguments
- dialects.verified_stmt("SELECT * FROM users |> CALL transform_data(col1 + col2)");
- dialects.verified_stmt("SELECT * FROM users |> CALL analyze_data('param1', 100, true)");
-
- // call pipe operator with aliases
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) AS al");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5) AS result_table");
- dialects.verified_stmt("SELECT * FROM users |> CALL namespace.func() AS my_alias");
-
- // multiple call pipe operators in sequence
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) |> CALL tvf2(arg2, arg3)");
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL transform(col1) |> CALL validate() |> CALL process(param)",
- );
-
- // multiple call pipe operators with aliases
- dialects.verified_stmt(
- "SELECT * FROM input_table |> CALL tvf1(arg1) AS step1 |> CALL tvf2(arg2) AS step2",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean_data |> CALL analyze(mode) AS results",
- );
-
- // call pipe operators mixed with other pipe operators
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL transform() |> WHERE status = 'active' |> CALL process(param)",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean |> SELECT col1, col2 |> CALL validate()",
- );
-
- // pivot pipe operator
- dialects.verified_stmt(
- "SELECT * FROM monthly_sales |> PIVOT(SUM(amount) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))",
- );
- dialects.verified_stmt("SELECT * FROM sales_data |> PIVOT(AVG(revenue) FOR region IN ('North', 'South', 'East', 'West'))");
-
- // pivot pipe operator with multiple aggregate functions
- dialects.verified_stmt("SELECT * FROM data |> PIVOT(SUM(sales) AS total_sales, COUNT(*) AS num_transactions FOR month IN ('Jan', 'Feb', 'Mar'))");
-
- // pivot pipe operator with compound column names
- dialects.verified_stmt("SELECT * FROM sales |> PIVOT(SUM(amount) FOR product.category IN ('Electronics', 'Clothing'))");
+/// Returns dialect configurations for pipe operator tests:
+/// 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+/// 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+fn pipe_dialects() -> [(TestedDialects, bool); 2] {
+ let from_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
+ [(from_first, true), (select_first, false)]
+}
+
+/// Macro to test pipe operator parsing with explicit input and canonical output.
+/// Usage: `test_pipe!(ctx, input = "...", canonical = "...")`
+macro_rules! test_pipe {
+ ($ctx:expr, input = $input:expr, canonical = $canonical:expr $(,)?) => {{
+ let (ref dialects, from_first) = $ctx;
+ let prefix = if from_first {
+ "FROM tbl"
+ } else {
+ "SELECT * FROM tbl"
+ };
+ dialects.verified_query_with_canonical(
+ &format!("{prefix} |> {}", $input),
+ &format!("{prefix} |> {}", $canonical),
+ );
+ }};
+}
- // pivot pipe operator mixed with other pipe operators
- dialects.verified_stmt("SELECT * FROM sales_data |> WHERE year = 2023 |> PIVOT(SUM(revenue) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))");
+#[test]
+fn parse_pipe_operator_as() {
+ for dialect in pipe_dialects() {
+ test_pipe!(dialect, input = "AS new_users", canonical = "AS new_users");
+ }
Review Comment:
Fair enough, doesn't offer much now after the previous cleanup :) Dropped; kept the improved clarity from breaking out the monolithic test block into clearer sections (is now one set of tests per pipe op), but otherwise it's back to the standard `verified_stmt` (and a `verified_query_with_canonical` or two), plus the extra test coverage for the bug π
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2737878332
##########
tests/sqlparser_common.rs:
##########
@@ -16200,304 +16198,702 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
-#[test]
-fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
-
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
-
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
-
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
-
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
-
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
-
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
-
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // union pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT BY NAME (SELECT * FROM admins)");
-
- // union pipe operator with BY NAME and multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator (BigQuery requires DISTINCT modifier for INTERSECT)
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins)");
-
- // intersect pipe operator with BY NAME modifier
- dialects
- .verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // intersect pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // except pipe operator (BigQuery requires DISTINCT modifier for EXCEPT)
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins)");
-
- // except pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // except pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // except pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // call pipe operator
- dialects.verified_stmt("SELECT * FROM users |> CALL my_function()");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5, 'test')");
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL namespace.function_name(col1, col2, 'literal')",
- );
-
- // call pipe operator with complex arguments
- dialects.verified_stmt("SELECT * FROM users |> CALL transform_data(col1 + col2)");
- dialects.verified_stmt("SELECT * FROM users |> CALL analyze_data('param1', 100, true)");
-
- // call pipe operator with aliases
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) AS al");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5) AS result_table");
- dialects.verified_stmt("SELECT * FROM users |> CALL namespace.func() AS my_alias");
-
- // multiple call pipe operators in sequence
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) |> CALL tvf2(arg2, arg3)");
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL transform(col1) |> CALL validate() |> CALL process(param)",
- );
-
- // multiple call pipe operators with aliases
- dialects.verified_stmt(
- "SELECT * FROM input_table |> CALL tvf1(arg1) AS step1 |> CALL tvf2(arg2) AS step2",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean_data |> CALL analyze(mode) AS results",
- );
-
- // call pipe operators mixed with other pipe operators
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL transform() |> WHERE status = 'active' |> CALL process(param)",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean |> SELECT col1, col2 |> CALL validate()",
- );
-
- // pivot pipe operator
- dialects.verified_stmt(
- "SELECT * FROM monthly_sales |> PIVOT(SUM(amount) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))",
- );
- dialects.verified_stmt("SELECT * FROM sales_data |> PIVOT(AVG(revenue) FOR region IN ('North', 'South', 'East', 'West'))");
-
- // pivot pipe operator with multiple aggregate functions
- dialects.verified_stmt("SELECT * FROM data |> PIVOT(SUM(sales) AS total_sales, COUNT(*) AS num_transactions FOR month IN ('Jan', 'Feb', 'Mar'))");
-
- // pivot pipe operator with compound column names
- dialects.verified_stmt("SELECT * FROM sales |> PIVOT(SUM(amount) FOR product.category IN ('Electronics', 'Clothing'))");
+/// Returns dialect configurations for pipe operator tests:
+/// 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+/// 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+fn pipe_dialects() -> [(TestedDialects, bool); 2] {
+ let from_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
+ [(from_first, true), (select_first, false)]
+}
+
+/// Macro to test pipe operator parsing with explicit input and canonical output.
+/// Usage: `test_pipe!(ctx, input = "...", canonical = "...")`
+macro_rules! test_pipe {
+ ($ctx:expr, input = $input:expr, canonical = $canonical:expr $(,)?) => {{
+ let (ref dialects, from_first) = $ctx;
+ let prefix = if from_first {
+ "FROM tbl"
+ } else {
+ "SELECT * FROM tbl"
+ };
+ dialects.verified_query_with_canonical(
+ &format!("{prefix} |> {}", $input),
+ &format!("{prefix} |> {}", $canonical),
+ );
+ }};
+}
- // pivot pipe operator mixed with other pipe operators
- dialects.verified_stmt("SELECT * FROM sales_data |> WHERE year = 2023 |> PIVOT(SUM(revenue) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))");
+#[test]
+fn parse_pipe_operator_as() {
+ for dialect in pipe_dialects() {
+ test_pipe!(dialect, input = "AS new_users", canonical = "AS new_users");
+ }
Review Comment:
Fair enough. Dropped it; kept the improved clarity from breaking out the monolithic test into clearer sections (one per pipe op), but otherwise it's back to the standard `verified_stmt` (and a `verified_query_with_canonical` or two) with the extra coverage for the bug π
##########
tests/sqlparser_common.rs:
##########
@@ -16200,304 +16198,702 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
-#[test]
-fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
-
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
-
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
-
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
-
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
-
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
-
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
-
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // union pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT BY NAME (SELECT * FROM admins)");
-
- // union pipe operator with BY NAME and multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator (BigQuery requires DISTINCT modifier for INTERSECT)
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins)");
-
- // intersect pipe operator with BY NAME modifier
- dialects
- .verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // intersect pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // except pipe operator (BigQuery requires DISTINCT modifier for EXCEPT)
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins)");
-
- // except pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // except pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // except pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // call pipe operator
- dialects.verified_stmt("SELECT * FROM users |> CALL my_function()");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5, 'test')");
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL namespace.function_name(col1, col2, 'literal')",
- );
-
- // call pipe operator with complex arguments
- dialects.verified_stmt("SELECT * FROM users |> CALL transform_data(col1 + col2)");
- dialects.verified_stmt("SELECT * FROM users |> CALL analyze_data('param1', 100, true)");
-
- // call pipe operator with aliases
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) AS al");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5) AS result_table");
- dialects.verified_stmt("SELECT * FROM users |> CALL namespace.func() AS my_alias");
-
- // multiple call pipe operators in sequence
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) |> CALL tvf2(arg2, arg3)");
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL transform(col1) |> CALL validate() |> CALL process(param)",
- );
-
- // multiple call pipe operators with aliases
- dialects.verified_stmt(
- "SELECT * FROM input_table |> CALL tvf1(arg1) AS step1 |> CALL tvf2(arg2) AS step2",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean_data |> CALL analyze(mode) AS results",
- );
-
- // call pipe operators mixed with other pipe operators
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL transform() |> WHERE status = 'active' |> CALL process(param)",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean |> SELECT col1, col2 |> CALL validate()",
- );
-
- // pivot pipe operator
- dialects.verified_stmt(
- "SELECT * FROM monthly_sales |> PIVOT(SUM(amount) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))",
- );
- dialects.verified_stmt("SELECT * FROM sales_data |> PIVOT(AVG(revenue) FOR region IN ('North', 'South', 'East', 'West'))");
-
- // pivot pipe operator with multiple aggregate functions
- dialects.verified_stmt("SELECT * FROM data |> PIVOT(SUM(sales) AS total_sales, COUNT(*) AS num_transactions FOR month IN ('Jan', 'Feb', 'Mar'))");
-
- // pivot pipe operator with compound column names
- dialects.verified_stmt("SELECT * FROM sales |> PIVOT(SUM(amount) FOR product.category IN ('Electronics', 'Clothing'))");
+/// Returns dialect configurations for pipe operator tests:
+/// 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+/// 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+fn pipe_dialects() -> [(TestedDialects, bool); 2] {
+ let from_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
+ [(from_first, true), (select_first, false)]
+}
+
+/// Macro to test pipe operator parsing with explicit input and canonical output.
+/// Usage: `test_pipe!(ctx, input = "...", canonical = "...")`
+macro_rules! test_pipe {
+ ($ctx:expr, input = $input:expr, canonical = $canonical:expr $(,)?) => {{
+ let (ref dialects, from_first) = $ctx;
+ let prefix = if from_first {
+ "FROM tbl"
+ } else {
+ "SELECT * FROM tbl"
+ };
+ dialects.verified_query_with_canonical(
+ &format!("{prefix} |> {}", $input),
+ &format!("{prefix} |> {}", $canonical),
+ );
+ }};
+}
- // pivot pipe operator mixed with other pipe operators
- dialects.verified_stmt("SELECT * FROM sales_data |> WHERE year = 2023 |> PIVOT(SUM(revenue) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))");
+#[test]
+fn parse_pipe_operator_as() {
+ for dialect in pipe_dialects() {
+ test_pipe!(dialect, input = "AS new_users", canonical = "AS new_users");
+ }
Review Comment:
Fair enough. Dropped it; kept the improved clarity from breaking out the monolithic test into clearer sections (one per pipe op), but otherwise it's back to the standard `verified_stmt` (and a `verified_query_with_canonical` or two), plus the extra coverage for the bug π
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2720222177
##########
tests/sqlparser_common.rs:
##########
@@ -16157,302 +16157,411 @@ fn parse_set_names() {
#[test]
fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
+ // Helper for testing pipe operators
+ struct PipeTest<'a> {
+ dialects: &'a TestedDialects,
+ from_first: bool,
+ }
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
+ impl PipeTest<'_> {
+ fn query(&self, table: &str, pipe_ops: &str) -> String {
+ if self.from_first {
+ format!("FROM {table} |> {pipe_ops}")
+ } else {
+ format!("SELECT * FROM {table} |> {pipe_ops}")
+ }
+ }
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
+ fn pipe(&self, table: &str, pipe_ops: &str) {
+ self.dialects.verified_stmt(&self.query(table, pipe_ops));
+ }
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
+ fn pipe_canonical(&self, table: &str, input: &str, canonical: &str) {
+ self.dialects.verified_query_with_canonical(
+ &self.query(table, input),
+ &self.query(table, canonical),
+ );
+ }
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
+ fn pipe_implicit_alias(&self, table: &str, expr: &str, alias: &str) {
+ // Test implicit alias syntax is canonicalized to explicit AS
+ // e.g., "SELECT id user_id" -> "SELECT id AS user_id"
+ self.dialects.verified_query_with_canonical(
+ &self.query(table, &format!("{expr} {alias}")),
+ &self.query(table, &format!("{expr} AS {alias}")),
+ );
+ }
+ }
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
+ // Test pipe operators with two dialect configurations:
+ // 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+ // 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+ let from_first_dialects =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first_dialects =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
+ // Run tests for both dialect configurations
+ for (dialects, from_first) in [
+ (&from_first_dialects, true),
+ (&select_first_dialects, false),
+ ] {
+ let t = PipeTest {
+ dialects,
+ from_first,
+ };
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
+ // 'select' pipe operator
Review Comment:
No problem - done ππ
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2737878332
##########
tests/sqlparser_common.rs:
##########
@@ -16200,304 +16198,702 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
-#[test]
-fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
-
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
-
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
-
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
-
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
-
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
-
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
-
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // union pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT BY NAME (SELECT * FROM admins)");
-
- // union pipe operator with BY NAME and multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator (BigQuery requires DISTINCT modifier for INTERSECT)
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins)");
-
- // intersect pipe operator with BY NAME modifier
- dialects
- .verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // intersect pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // except pipe operator (BigQuery requires DISTINCT modifier for EXCEPT)
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins)");
-
- // except pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // except pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // except pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // call pipe operator
- dialects.verified_stmt("SELECT * FROM users |> CALL my_function()");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5, 'test')");
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL namespace.function_name(col1, col2, 'literal')",
- );
-
- // call pipe operator with complex arguments
- dialects.verified_stmt("SELECT * FROM users |> CALL transform_data(col1 + col2)");
- dialects.verified_stmt("SELECT * FROM users |> CALL analyze_data('param1', 100, true)");
-
- // call pipe operator with aliases
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) AS al");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5) AS result_table");
- dialects.verified_stmt("SELECT * FROM users |> CALL namespace.func() AS my_alias");
-
- // multiple call pipe operators in sequence
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) |> CALL tvf2(arg2, arg3)");
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL transform(col1) |> CALL validate() |> CALL process(param)",
- );
-
- // multiple call pipe operators with aliases
- dialects.verified_stmt(
- "SELECT * FROM input_table |> CALL tvf1(arg1) AS step1 |> CALL tvf2(arg2) AS step2",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean_data |> CALL analyze(mode) AS results",
- );
-
- // call pipe operators mixed with other pipe operators
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL transform() |> WHERE status = 'active' |> CALL process(param)",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean |> SELECT col1, col2 |> CALL validate()",
- );
-
- // pivot pipe operator
- dialects.verified_stmt(
- "SELECT * FROM monthly_sales |> PIVOT(SUM(amount) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))",
- );
- dialects.verified_stmt("SELECT * FROM sales_data |> PIVOT(AVG(revenue) FOR region IN ('North', 'South', 'East', 'West'))");
-
- // pivot pipe operator with multiple aggregate functions
- dialects.verified_stmt("SELECT * FROM data |> PIVOT(SUM(sales) AS total_sales, COUNT(*) AS num_transactions FOR month IN ('Jan', 'Feb', 'Mar'))");
-
- // pivot pipe operator with compound column names
- dialects.verified_stmt("SELECT * FROM sales |> PIVOT(SUM(amount) FOR product.category IN ('Electronics', 'Clothing'))");
+/// Returns dialect configurations for pipe operator tests:
+/// 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+/// 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+fn pipe_dialects() -> [(TestedDialects, bool); 2] {
+ let from_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
+ [(from_first, true), (select_first, false)]
+}
+
+/// Macro to test pipe operator parsing with explicit input and canonical output.
+/// Usage: `test_pipe!(ctx, input = "...", canonical = "...")`
+macro_rules! test_pipe {
+ ($ctx:expr, input = $input:expr, canonical = $canonical:expr $(,)?) => {{
+ let (ref dialects, from_first) = $ctx;
+ let prefix = if from_first {
+ "FROM tbl"
+ } else {
+ "SELECT * FROM tbl"
+ };
+ dialects.verified_query_with_canonical(
+ &format!("{prefix} |> {}", $input),
+ &format!("{prefix} |> {}", $canonical),
+ );
+ }};
+}
- // pivot pipe operator mixed with other pipe operators
- dialects.verified_stmt("SELECT * FROM sales_data |> WHERE year = 2023 |> PIVOT(SUM(revenue) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))");
+#[test]
+fn parse_pipe_operator_as() {
+ for dialect in pipe_dialects() {
+ test_pipe!(dialect, input = "AS new_users", canonical = "AS new_users");
+ }
Review Comment:
Fair enough. Dropped it; kept the improved clarity from breaking out the monolithic test into clearer sections (one per pipe op), but otherwise it's back to the standard `verified_stmt` (and occasional `verified_query_with_canonical`) with the extra coverage for the bug π
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2720222177
##########
tests/sqlparser_common.rs:
##########
@@ -16157,302 +16157,411 @@ fn parse_set_names() {
#[test]
fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
+ // Helper for testing pipe operators
+ struct PipeTest<'a> {
+ dialects: &'a TestedDialects,
+ from_first: bool,
+ }
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
+ impl PipeTest<'_> {
+ fn query(&self, table: &str, pipe_ops: &str) -> String {
+ if self.from_first {
+ format!("FROM {table} |> {pipe_ops}")
+ } else {
+ format!("SELECT * FROM {table} |> {pipe_ops}")
+ }
+ }
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
+ fn pipe(&self, table: &str, pipe_ops: &str) {
+ self.dialects.verified_stmt(&self.query(table, pipe_ops));
+ }
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
+ fn pipe_canonical(&self, table: &str, input: &str, canonical: &str) {
+ self.dialects.verified_query_with_canonical(
+ &self.query(table, input),
+ &self.query(table, canonical),
+ );
+ }
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
+ fn pipe_implicit_alias(&self, table: &str, expr: &str, alias: &str) {
+ // Test implicit alias syntax is canonicalized to explicit AS
+ // e.g., "SELECT id user_id" -> "SELECT id AS user_id"
+ self.dialects.verified_query_with_canonical(
+ &self.query(table, &format!("{expr} {alias}")),
+ &self.query(table, &format!("{expr} AS {alias}")),
+ );
+ }
+ }
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
+ // Test pipe operators with two dialect configurations:
+ // 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+ // 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+ let from_first_dialects =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first_dialects =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
+ // Run tests for both dialect configurations
+ for (dialects, from_first) in [
+ (&from_first_dialects, true),
+ (&select_first_dialects, false),
+ ] {
+ let t = PipeTest {
+ dialects,
+ from_first,
+ };
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
+ // 'select' pipe operator
Review Comment:
No problem - done ππ Still streamlined (and testing multiple forms), but now shows the query input and the expected canonical form explicitly.
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "alexander-beedie (via GitHub)" <gi...@apache.org>.
alexander-beedie commented on code in PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156#discussion_r2737878332
##########
tests/sqlparser_common.rs:
##########
@@ -16200,304 +16198,702 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
-#[test]
-fn parse_pipeline_operator() {
- let dialects = all_dialects_where(|d| d.supports_pipe_operator());
-
- // select pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SELECT id");
- dialects.verified_stmt("SELECT * FROM users |> SELECT id, name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> SELECT id user_id",
- "SELECT * FROM users |> SELECT id AS user_id",
- );
- dialects.verified_stmt("SELECT * FROM users |> SELECT id AS user_id");
-
- // extend pipe operator
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id + 1 AS new_id");
- dialects.verified_stmt("SELECT * FROM users |> EXTEND id AS new_id, name AS new_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> EXTEND id user_id",
- "SELECT * FROM users |> EXTEND id AS user_id",
- );
-
- // set pipe operator
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1");
- dialects.verified_stmt("SELECT * FROM users |> SET id = id + 1, name = name + ' Doe'");
-
- // drop pipe operator
- dialects.verified_stmt("SELECT * FROM users |> DROP id");
- dialects.verified_stmt("SELECT * FROM users |> DROP id, name");
-
- // as pipe operator
- dialects.verified_stmt("SELECT * FROM users |> AS new_users");
-
- // limit pipe operator
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 OFFSET 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> LIMIT 5");
- dialects.verified_stmt("SELECT * FROM users |> LIMIT 10 |> WHERE true");
-
- // where pipe operator
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 AND name = 'John'");
- dialects.verified_stmt("SELECT * FROM users |> WHERE id = 1 OR name = 'John'");
-
- // aggregate pipe operator full table
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*)");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> AGGREGATE COUNT(*) total_users",
- "SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users",
- );
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*) AS total_users");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE COUNT(*), MIN(id)");
-
- // aggregate pipe opeprator with grouping
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE SUM(o_totalprice) AS price, COUNT(*) AS cnt GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects.verified_stmt(
- "SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate) AS year",
- );
- dialects
- .verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY EXTRACT(YEAR FROM o_orderdate)");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) GROUP BY a, b");
- dialects.verified_stmt("SELECT * FROM users |> AGGREGATE SUM(c) ASC");
-
- // order by pipe operator
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id ASC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
- dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
-
- // tablesample pipe operator
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
- dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
-
- // rename pipe operator
- dialects.verified_stmt("SELECT * FROM users |> RENAME old_name AS new_name");
- dialects.verified_stmt("SELECT * FROM users |> RENAME id AS user_id, name AS user_name");
- dialects.verified_query_with_canonical(
- "SELECT * FROM users |> RENAME id user_id",
- "SELECT * FROM users |> RENAME id AS user_id",
- );
-
- // union pipe operator
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION (SELECT * FROM admins)");
-
- // union pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION ALL (SELECT * FROM admins), (SELECT * FROM guests)",
- );
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT (SELECT * FROM admins), (SELECT * FROM guests), (SELECT * FROM employees)");
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // union pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION ALL BY NAME (SELECT * FROM admins)");
- dialects.verified_stmt("SELECT * FROM users |> UNION DISTINCT BY NAME (SELECT * FROM admins)");
-
- // union pipe operator with BY NAME and multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> UNION BY NAME (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator (BigQuery requires DISTINCT modifier for INTERSECT)
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins)");
-
- // intersect pipe operator with BY NAME modifier
- dialects
- .verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // intersect pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> INTERSECT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // intersect pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> INTERSECT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // except pipe operator (BigQuery requires DISTINCT modifier for EXCEPT)
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins)");
-
- // except pipe operator with BY NAME modifier
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins)");
-
- // except pipe operator with multiple queries
- dialects.verified_stmt(
- "SELECT * FROM users |> EXCEPT DISTINCT (SELECT * FROM admins), (SELECT * FROM guests)",
- );
-
- // except pipe operator with BY NAME and multiple queries
- dialects.verified_stmt("SELECT * FROM users |> EXCEPT DISTINCT BY NAME (SELECT * FROM admins), (SELECT * FROM guests)");
-
- // call pipe operator
- dialects.verified_stmt("SELECT * FROM users |> CALL my_function()");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5, 'test')");
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL namespace.function_name(col1, col2, 'literal')",
- );
-
- // call pipe operator with complex arguments
- dialects.verified_stmt("SELECT * FROM users |> CALL transform_data(col1 + col2)");
- dialects.verified_stmt("SELECT * FROM users |> CALL analyze_data('param1', 100, true)");
-
- // call pipe operator with aliases
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) AS al");
- dialects.verified_stmt("SELECT * FROM users |> CALL process_data(5) AS result_table");
- dialects.verified_stmt("SELECT * FROM users |> CALL namespace.func() AS my_alias");
-
- // multiple call pipe operators in sequence
- dialects.verified_stmt("SELECT * FROM input_table |> CALL tvf1(arg1) |> CALL tvf2(arg2, arg3)");
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL transform(col1) |> CALL validate() |> CALL process(param)",
- );
-
- // multiple call pipe operators with aliases
- dialects.verified_stmt(
- "SELECT * FROM input_table |> CALL tvf1(arg1) AS step1 |> CALL tvf2(arg2) AS step2",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean_data |> CALL analyze(mode) AS results",
- );
-
- // call pipe operators mixed with other pipe operators
- dialects.verified_stmt(
- "SELECT * FROM users |> CALL transform() |> WHERE status = 'active' |> CALL process(param)",
- );
- dialects.verified_stmt(
- "SELECT * FROM data |> CALL preprocess() AS clean |> SELECT col1, col2 |> CALL validate()",
- );
-
- // pivot pipe operator
- dialects.verified_stmt(
- "SELECT * FROM monthly_sales |> PIVOT(SUM(amount) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))",
- );
- dialects.verified_stmt("SELECT * FROM sales_data |> PIVOT(AVG(revenue) FOR region IN ('North', 'South', 'East', 'West'))");
-
- // pivot pipe operator with multiple aggregate functions
- dialects.verified_stmt("SELECT * FROM data |> PIVOT(SUM(sales) AS total_sales, COUNT(*) AS num_transactions FOR month IN ('Jan', 'Feb', 'Mar'))");
-
- // pivot pipe operator with compound column names
- dialects.verified_stmt("SELECT * FROM sales |> PIVOT(SUM(amount) FOR product.category IN ('Electronics', 'Clothing'))");
+/// Returns dialect configurations for pipe operator tests:
+/// 1. Dialects supporting FROM-first syntax (e.g., "FROM users |> ...")
+/// 2. Dialects requiring SELECT-first syntax (e.g., "SELECT * FROM users |> ...")
+fn pipe_dialects() -> [(TestedDialects, bool); 2] {
+ let from_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && d.supports_from_first_select());
+ let select_first =
+ all_dialects_where(|d| d.supports_pipe_operator() && !d.supports_from_first_select());
+ [(from_first, true), (select_first, false)]
+}
+
+/// Macro to test pipe operator parsing with explicit input and canonical output.
+/// Usage: `test_pipe!(ctx, input = "...", canonical = "...")`
+macro_rules! test_pipe {
+ ($ctx:expr, input = $input:expr, canonical = $canonical:expr $(,)?) => {{
+ let (ref dialects, from_first) = $ctx;
+ let prefix = if from_first {
+ "FROM tbl"
+ } else {
+ "SELECT * FROM tbl"
+ };
+ dialects.verified_query_with_canonical(
+ &format!("{prefix} |> {}", $input),
+ &format!("{prefix} |> {}", $canonical),
+ );
+ }};
+}
- // pivot pipe operator mixed with other pipe operators
- dialects.verified_stmt("SELECT * FROM sales_data |> WHERE year = 2023 |> PIVOT(SUM(revenue) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))");
+#[test]
+fn parse_pipe_operator_as() {
+ for dialect in pipe_dialects() {
+ test_pipe!(dialect, input = "AS new_users", canonical = "AS new_users");
+ }
Review Comment:
Fair enough. Dropped it; kept the improved clarity of breaking out the monolithic test into clearer sections (one per pipe op), but otherwise it's back to the standard `verified_stmt` (and occasional `verified_query_with_canonical`) π
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org
Re: [PR] Fix identifier parsing not breaking on the `|>` pipe operator [datafusion-sqlparser-rs]
Posted by "iffyio (via GitHub)" <gi...@apache.org>.
iffyio merged PR #2156:
URL: https://github.com/apache/datafusion-sqlparser-rs/pull/2156
--
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: github-unsubscribe@datafusion.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscribe@datafusion.apache.org
For additional commands, e-mail: github-help@datafusion.apache.org