You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/05/06 14:57:55 UTC

(datafusion-sqlparser-rs) branch main updated: BigQuery: Parse WITH CONNECTION on CREATE EXTERNAL TABLE (#2326)

This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 7c78d138 BigQuery: Parse WITH CONNECTION on CREATE EXTERNAL TABLE (#2326)
7c78d138 is described below

commit 7c78d138ae4b69359ad38b0996eda7de5e1a356b
Author: Corey Fritz <cf...@montecarlodata.com>
AuthorDate: Wed May 6 08:39:38 2026 -0600

    BigQuery: Parse WITH CONNECTION on CREATE EXTERNAL TABLE (#2326)
---
 src/ast/ddl.rs                       |  6 ++++++
 src/ast/helpers/stmt_create_table.rs | 11 +++++++++++
 src/ast/spans.rs                     |  1 +
 src/parser/mod.rs                    |  7 +++++++
 tests/sqlparser_bigquery.rs          | 25 +++++++++++++++++++++++++
 tests/sqlparser_duckdb.rs            |  1 +
 tests/sqlparser_mssql.rs             |  2 ++
 tests/sqlparser_postgres.rs          |  1 +
 8 files changed, 54 insertions(+)

diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 62a8a71a..0a93f5b7 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -3020,6 +3020,9 @@ pub struct CreateTable {
     /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
     /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
     pub external_volume: Option<String>,
+    /// `WITH CONNECTION` clause.
+    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_external_table_statement)
+    pub with_connection: Option<ObjectName>,
     /// Snowflake "BASE_LOCATION" clause for Iceberg tables
     /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
     pub base_location: Option<String>,
@@ -3269,6 +3272,9 @@ impl fmt::Display for CreateTable {
         if let Some(cluster_by) = self.cluster_by.as_ref() {
             write!(f, " CLUSTER BY {cluster_by}")?;
         }
+        if let Some(with_connection) = &self.with_connection {
+            write!(f, " WITH CONNECTION {with_connection}")?;
+        }
         if let options @ CreateTableOptions::Options(_) = &self.table_options {
             write!(f, " {options}")?;
         }
diff --git a/src/ast/helpers/stmt_create_table.rs b/src/ast/helpers/stmt_create_table.rs
index fc81d3b8..9ec9ab28 100644
--- a/src/ast/helpers/stmt_create_table.rs
+++ b/src/ast/helpers/stmt_create_table.rs
@@ -157,6 +157,9 @@ pub struct CreateTableBuilder {
     pub base_location: Option<String>,
     /// Optional external volume identifier.
     pub external_volume: Option<String>,
+    /// `WITH CONNECTION` clause.
+    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_external_table_statement)
+    pub with_connection: Option<ObjectName>,
     /// Optional catalog name.
     pub catalog: Option<String>,
     /// Optional catalog synchronization option.
@@ -241,6 +244,7 @@ impl CreateTableBuilder {
             with_tags: None,
             base_location: None,
             external_volume: None,
+            with_connection: None,
             catalog: None,
             catalog_sync: None,
             storage_serialization_policy: None,
@@ -497,6 +501,11 @@ impl CreateTableBuilder {
         self.external_volume = external_volume;
         self
     }
+    /// Set the `WITH CONNECTION` clause.
+    pub fn with_connection(mut self, with_connection: Option<ObjectName>) -> Self {
+        self.with_connection = with_connection;
+        self
+    }
     /// Set the catalog name for the table.
     pub fn catalog(mut self, catalog: Option<String>) -> Self {
         self.catalog = catalog;
@@ -630,6 +639,7 @@ impl CreateTableBuilder {
             with_tags: self.with_tags,
             base_location: self.base_location,
             external_volume: self.external_volume,
+            with_connection: self.with_connection,
             catalog: self.catalog,
             catalog_sync: self.catalog_sync,
             storage_serialization_policy: self.storage_serialization_policy,
@@ -714,6 +724,7 @@ impl From<CreateTable> for CreateTableBuilder {
             with_tags: table.with_tags,
             base_location: table.base_location,
             external_volume: table.external_volume,
+            with_connection: table.with_connection,
             catalog: table.catalog,
             catalog_sync: table.catalog_sync,
             storage_serialization_policy: table.storage_serialization_policy,
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 343d99e7..f6ba8954 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -589,6 +589,7 @@ impl Spanned for CreateTable {
             with_storage_lifecycle_policy: _,   // todo, Snowflake specific
             with_tags: _,                       // todo, Snowflake specific
             external_volume: _,                 // todo, Snowflake specific
+            with_connection: _,                 // todo, BigQuery external table connection
             base_location: _,                   // todo, Snowflake specific
             catalog: _,                         // todo, Snowflake specific
             catalog_sync: _,                    // todo, Snowflake specific
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 3d4b3095..07497b04 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -6418,6 +6418,12 @@ impl<'a> Parser<'a> {
             None
         };
         let location = hive_formats.as_ref().and_then(|hf| hf.location.clone());
+
+        let with_connection = if self.parse_keywords(&[Keyword::WITH, Keyword::CONNECTION]) {
+            Some(self.parse_object_name(false)?)
+        } else {
+            None
+        };
         let table_properties = self.parse_options(Keyword::TBLPROPERTIES)?;
         let table_options = if !table_properties.is_empty() {
             CreateTableOptions::TableProperties(table_properties)
@@ -6432,6 +6438,7 @@ impl<'a> Parser<'a> {
             .hive_distribution(hive_distribution)
             .hive_formats(hive_formats)
             .table_options(table_options)
+            .with_connection(with_connection)
             .or_replace(or_replace)
             .if_not_exists(if_not_exists)
             .external(true)
diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs
index 212607e0..f6d4483c 100644
--- a/tests/sqlparser_bigquery.rs
+++ b/tests/sqlparser_bigquery.rs
@@ -2203,6 +2203,31 @@ fn parse_big_query_declare() {
     );
 }
 
+#[test]
+fn parse_bigquery_create_external_table_with_connection() {
+    bigquery().one_statement_parses_to(
+        concat!(
+            "CREATE OR REPLACE EXTERNAL TABLE `proj.ds.tbl` ",
+            "WITH CONNECTION `projects/proj/locations/us/connections/c` ",
+            r#"OPTIONS(format = "ICEBERG", uris = ["gs://b/m.json"])"#,
+        ),
+        concat!(
+            "CREATE OR REPLACE EXTERNAL TABLE `proj`.`ds`.`tbl` () ",
+            "WITH CONNECTION `projects/proj/locations/us/connections/c` ",
+            r#"OPTIONS(format = "ICEBERG", uris = ["gs://b/m.json"])"#,
+        ),
+    );
+    bigquery().one_statement_parses_to(
+        "CREATE EXTERNAL TABLE t WITH CONNECTION c",
+        "CREATE EXTERNAL TABLE t () WITH CONNECTION c",
+    );
+    bigquery().verified_stmt(concat!(
+        "CREATE EXTERNAL TABLE t (a INT64, b STRING) ",
+        r#"WITH CONNECTION c OPTIONS(uris = ["gs://x"])"#,
+    ));
+    bigquery().verified_stmt(r#"CREATE EXTERNAL TABLE t (a INT64) OPTIONS(uris = ["gs://x"])"#);
+}
+
 fn bigquery() -> TestedDialects {
     TestedDialects::new(vec![Box::new(BigQueryDialect {})])
 }
diff --git a/tests/sqlparser_duckdb.rs b/tests/sqlparser_duckdb.rs
index 548ad27c..86c76581 100644
--- a/tests/sqlparser_duckdb.rs
+++ b/tests/sqlparser_duckdb.rs
@@ -780,6 +780,7 @@ fn test_duckdb_union_datatype() {
             with_tags: Default::default(),
             base_location: Default::default(),
             external_volume: Default::default(),
+            with_connection: Default::default(),
             catalog: Default::default(),
             catalog_sync: Default::default(),
             storage_serialization_policy: Default::default(),
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index d784c74a..6e866746 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -1999,6 +1999,7 @@ fn parse_create_table_with_valid_options() {
                 with_tags: None,
                 base_location: None,
                 external_volume: None,
+                with_connection: None,
                 catalog: None,
                 catalog_sync: None,
                 storage_serialization_policy: None,
@@ -2176,6 +2177,7 @@ fn parse_create_table_with_identity_column() {
                 with_tags: None,
                 base_location: None,
                 external_volume: None,
+                with_connection: None,
                 catalog: None,
                 catalog_sync: None,
                 storage_serialization_policy: None,
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 369e7fc5..11e76dbc 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -6702,6 +6702,7 @@ fn parse_trigger_related_functions() {
             with_tags: None,
             base_location: None,
             external_volume: None,
+            with_connection: None,
             catalog: None,
             catalog_sync: None,
             storage_serialization_policy: None,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org