Skip to content

Commit 360cff4

Browse files
wojpadloWojciech Padłoclaude
authored
Task LAV-2921: Snowflake-managed Iceberg clone: CREATE ICEBERG TABLE … CLONE and Iceberg tables inside SCHEMA / DATABASE clones (#3299)
* task LAV-2921: WIP — commit stranded agent work * Task LAV-2921: clone managed & dynamic Iceberg tables inside SCHEMA/DATABASE clone Route managed Iceberg tables through the Iceberg-aware per-table clone (auto mode) and dynamic Iceberg tables through the DT clone loop so a container clone reproduces them as Iceberg / dynamic Iceberg tables (is_iceberg=Y, is_dynamic=Y, SUSPENDED, is_clone). Add real-Snowflake-captured compat tests for schema and database clones over managed and dynamic Iceberg sources. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Task LAV-2921: direct Iceberg clone time-travel anchors + docs Add AT/BEFORE (TIMESTAMP/OFFSET/STATEMENT) coverage for CREATE ICEBERG TABLE … CLONE (reusing the table-level time-travel clone path, incl. the out-of-window and statement-not-found errors), and update docs/architecture/iceberg-tables.md CLONE rows to the implemented behaviour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Task LAV-2921: skip externally-managed Iceberg tables in container clone An externally-managed / catalog-linked Iceberg table (iceberg_tables row with catalog_table_name or metadata_file_path) is not caught by is_external_table, so the container plain-clone loop would drop it to a plain heap — which real Snowflake never produces for an Iceberg source. Skip it like external tables. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Wojciech Padło <wojciech.padlo@localstack.cloud> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f4c9219 commit 360cff4

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

‎src/dialect/snowflake.rs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,14 @@ impl SnowflakeDialect {
784784
_ => {}
785785
}
786786

787+
// `CREATE [OR REPLACE] TRANSIENT ICEBERG TABLE` — the TRANSIENT
788+
// modifier may precede ICEBERG (mirrors TRANSIENT DYNAMIC above);
789+
// the modifier group only matches one keyword, so pick up ICEBERG
790+
// here after a leading TRANSIENT.
791+
if transient && !iceberg && parser.parse_keyword(Keyword::ICEBERG) {
792+
iceberg = true;
793+
}
794+
787795
if scoped && !temporary {
788796
return Some(parser.expected("TEMPORARY after SCOPED", parser.peek_token()));
789797
}
@@ -3087,13 +3095,15 @@ pub fn parse_create_table(
30873095

30883096
// Snowflake-managed Iceberg tables require BASE_LOCATION. Tables bound to
30893097
// an external catalog integration (an explicit non-SNOWFLAKE CATALOG, or
3090-
// CATALOG_TABLE_NAME for externally-managed reads) do not.
3098+
// CATALOG_TABLE_NAME for externally-managed reads) do not, and neither does
3099+
// a clone (CREATE ICEBERG TABLE … CLONE inherits the source's location).
30913100
let external_catalog = builder
30923101
.catalog
30933102
.as_deref()
30943103
.is_some_and(|c| !c.eq_ignore_ascii_case("SNOWFLAKE"));
30953104
if iceberg
30963105
&& !dynamic
3106+
&& builder.clone.is_none()
30973107
&& builder.base_location.is_none()
30983108
&& builder.catalog_table_name.is_none()
30993109
&& builder.metadata_file_path.is_none()

0 commit comments

Comments
 (0)