BigQuery: Parse WITH CONNECTION on CREATE EXTERNAL TABLE (#2326)
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 62a8a71..0a93f5b 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -3020,6 +3020,9 @@
/// 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 @@
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 fc81d3b..9ec9ab2 100644
--- a/src/ast/helpers/stmt_create_table.rs
+++ b/src/ast/helpers/stmt_create_table.rs
@@ -157,6 +157,9 @@
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 @@
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 @@
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 @@
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 @@
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 343d99e..f6ba895 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -589,6 +589,7 @@
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 3d4b309..07497b0 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -6418,6 +6418,12 @@
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 @@
.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 212607e..f6d4483 100644
--- a/tests/sqlparser_bigquery.rs
+++ b/tests/sqlparser_bigquery.rs
@@ -2203,6 +2203,31 @@
);
}
+#[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 548ad27..86c7658 100644
--- a/tests/sqlparser_duckdb.rs
+++ b/tests/sqlparser_duckdb.rs
@@ -780,6 +780,7 @@
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 d784c74..6e86674 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -1999,6 +1999,7 @@
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 @@
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 369e7fc..11e76db 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -6702,6 +6702,7 @@
with_tags: None,
base_location: None,
external_volume: None,
+ with_connection: None,
catalog: None,
catalog_sync: None,
storage_serialization_policy: None,