Openflow Connector for MySQL: Iceberg table destinations

The Openflow Connector for MySQL supports writing to Snowflake-managed Apache Apache Iceberg™ tables as an opt-in destination format. Iceberg v2 and v3 are both supported. Setting Table Storage Format = ICEBERG in the connector’s parameter context is the only change required. All Iceberg storage settings (external volume, catalog, version, and serialization policy) are inherited from the Snowflake destination database defaults.

Storage can be either Snowflake-managed (EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED') or a customer-configured external volume. With Snowflake-managed storage, no external cloud storage or IAM grants are required. For more information, see Snowflake storage for Iceberg tables.

Existing connectors using standard tables aren’t affected.

Prerequisites

  • Openflow runtime: An existing runtime to host the connector.
  • MySQL source configured for CDC: Binary logging enabled (log_bin = ON, binlog_format = ROW, binlog_row_image = FULL), a user with REPLICATION SLAVE and REPLICATION CLIENT privileges, and a sufficiently long binlog_expire_logs_seconds for snapshot reconciliation. For details, see Set up the Openflow Connector for MySQL.
  • Snowflake external volume (customer-managed storage only): An external volume configured for Iceberg storage, with USAGE granted to the connector’s Snowflake role. See CREATE EXTERNAL VOLUME. Not required when using Snowflake-managed storage (EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED').
  • Snowflake destination database: An existing database configured with Iceberg parameters (next section).

Step 1: Configure the Snowflake destination database

Set the Iceberg defaults on the destination database. The connector reads these defaults at runtime, so no per-connector Iceberg configuration is needed beyond Table Storage Format.

Option A: Snowflake-managed storage

With Snowflake-managed storage, Snowflake stores and manages the Iceberg table files for you. No external cloud storage or IAM grants are required.

CREATE DATABASE <db>
  EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED'
  ICEBERG_VERSION_DEFAULT = <2|3>
  STORAGE_SERIALIZATION_POLICY = <COMPATIBLE|OPTIMIZED>;

To configure an existing database:

ALTER DATABASE <db> SET
  EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED'
  ICEBERG_VERSION_DEFAULT = <2|3>
  STORAGE_SERIALIZATION_POLICY = <COMPATIBLE|OPTIMIZED>;

Option B: Customer-configured external volume

If you need to keep table files in your own cloud storage, configure the database with your external volume:

CREATE DATABASE <db>
  EXTERNAL_VOLUME = '<volume>'
  ICEBERG_VERSION_DEFAULT = <2|3>
  STORAGE_SERIALIZATION_POLICY = <COMPATIBLE|OPTIMIZED>;

To configure an existing database:

ALTER DATABASE <db> SET
  EXTERNAL_VOLUME = '<volume>'
  ICEBERG_VERSION_DEFAULT = <2|3>
  STORAGE_SERIALIZATION_POLICY = <COMPATIBLE|OPTIMIZED>;
ParameterRequiredNotes
EXTERNAL_VOLUMEYesThe external volume for Iceberg file storage.
ICEBERG_VERSION_DEFAULTYes

2 or 3. The connector fails fast if this isn’t set.

STORAGE_SERIALIZATION_POLICYYes

COMPATIBLE produces Parquet files readable by external engines. OPTIMIZED enables Snowflake-specific query optimizations. Choose based on your data query needs. For more information, see STORAGE_SERIALIZATION_POLICY.

Note

CATALOG = 'SNOWFLAKE' is set automatically by the connector on each CREATE ICEBERG TABLE statement. Don’t set it at the database level.

The base location for each table is auto-derived using the flat layout: STORAGE_BASE_URL/database/schema/table_name.randomId/[data | metadata]/. No user configuration is needed.

If using a customer-configured external volume (Option B), grant the connector’s Snowflake role USAGE on the external volume:

GRANT USAGE ON EXTERNAL VOLUME <volume> TO ROLE <openflow_role>;

This step is not required for Snowflake-managed storage.

Step 2: Set Table Storage Format in the connector’s parameter context

Set the Table Storage Format parameter to ICEBERG in the connector’s destination parameter context. The default is STANDARD.

For the full connector creation and configuration workflow, see Set up the Openflow Connector for MySQL.

Step 3: Start and verify

Start the connector as usual. After the initial snapshot completes, verify the destination tables are Iceberg:

-- Confirm the table is Iceberg
SELECT GET_DDL('TABLE', '<db>.<schema>.<table>');

-- Confirm the Iceberg version on the database
SHOW PARAMETERS LIKE 'ICEBERG_VERSION_DEFAULT' IN DATABASE <db>;

Known limitations

  • Tri-Secret Secure accounts and Snowflake-managed storage: Accounts with Tri-Secret Secure (TSS) enabled may be unable to create new Snowflake-managed Iceberg tables on Snowflake storage. For details, see Encryption.
  • Incompatible type changes on the source cause table failure: Only same-family type widening is allowed on Iceberg tables (for example, int to long, float to double, or decimal(P,S) to decimal(P',S) with wider precision). Cross-family changes such as int to decimal, long to string, or int to boolean are not allowed. If a source column’s type changes to an incompatible Iceberg type, the table is marked as failed and requires a rebootstrap.
  • BIGINT to BIGINT UNSIGNED schema evolution not allowed: Signed BIGINT maps to long while BIGINT UNSIGNED maps to decimal(20,0). Iceberg does not allow promotion from long to decimal, so this schema change on the source will fail replication.
  • Do not change Table Storage Format or Iceberg version after the connector starts: The connector’s Table Storage Format and the destination database’s Iceberg version should not be modified while the connector is running or stopped. Mixing settings across destination tables is not supported. To switch, follow the steps in Switching table storage format or Iceberg version.

Type mapping reference

The following table shows how MySQL types map to Snowflake standard and Iceberg destination types:

MySQL typeSnowflake (Standard)Iceberg v3Iceberg v2
TINYINT / SMALLINT / MEDIUMINT (signed or unsigned)INTintint
INT (signed)INTintint
INT UNSIGNEDINTlonglong
BIGINT (signed)INTlonglong
BIGINT UNSIGNEDINTdecimal(20,0)decimal(20,0)
YEARINTintint
FLOAT (signed/unsigned)FLOATdoubledouble
DOUBLE (signed/unsigned)FLOATdoubledouble
DECIMAL(P,S) (P ≤ 38)NUMBER(P,S)decimal(P,S)decimal(P,S)
DECIMAL(P,S) (P > 38)TEXTstringstring
BOOLEAN / BOOLINTintint
DATEDATEdatedate
TIMETIMEtimetime
DATETIMETIMESTAMP_NTZtimestamptimestamp
TIMESTAMPTIMESTAMP_TZtimestamptztimestamptz
CHAR / VARCHAR / TEXT / TINYTEXT / MEDIUMTEXT / LONGTEXTTEXTstringstring
ENUM / SETTEXTstringstring
BITTEXTstringstring
BINARY / VARBINARY / BLOB / TINYBLOB / MEDIUMBLOB / LONGBLOBBINARYbinarybinary
JSONVARIANTvariantstring
GEOMETRY familyTEXTstringstring

Source types not listed in the table are mapped to TEXT on standard tables and string on Iceberg tables.

Switching table storage format or Iceberg version

Switching between Standard and Iceberg, or between Iceberg v2 and v3, requires recreating the connector. Follow these steps:

  1. Stop the connector.
  2. Delete the process group in Openflow.
  3. Manually clean up the destination database (drop the replicated schemas/tables, or use a new database).
  4. Reimport the connector with the new Table Storage Format or Iceberg version configured on the destination database.

This ensures all connector state is correctly cleaned up within Openflow. The new connector performs a fresh snapshot into the destination.

References