Skip to main content

Overview

Duckling provides comprehensive MySQL 8 data type support with automatic mapping to DuckDB types. All standard MySQL types are supported through both full sync (Appender API) and incremental sync (CDC) paths.

Type Mapping Reference

The following table shows the complete mapping between MySQL 8 types and DuckDB types:
MySQL TypeDuckDB ColumnAppender MethodFull SyncIncremental SyncCDC
TINYINTTINYINTappendTinyInt
SMALLINTSMALLINTappendSmallInt
MEDIUMINTBIGINTappendBigInt
INTBIGINTappendBigInt
INT UNSIGNEDBIGINTappendBigInt
BIGINTBIGINTappendBigInt
BIGINT UNSIGNEDBIGINTappendBigInt(BigInt)
FLOATFLOATappendFloat
DOUBLEDOUBLEappendDouble
DECIMAL(p,s)DECIMALappendVarchar
CHAR(n)VARCHARappendVarchar
VARCHAR(n)VARCHARappendVarchar
TINYTEXTTEXTappendVarchar
TEXTTEXTappendVarchar
MEDIUMTEXTTEXTappendVarchar
LONGTEXTTEXTappendVarchar
BINARY(n)BLOBappendBlob
VARBINARY(n)BLOBappendBlob
TINYBLOBBLOBappendBlob
BLOBBLOBappendBlob
MEDIUMBLOBBLOBappendBlob
LONGBLOBBLOBappendBlob
JSONJSONappendVarchar
ENUMVARCHARappendVarchar
SETVARCHARappendVarchar
DATEDATEappendVarchar (auto)
TIMETIMEappendTime
TIME(6)TIMEappendTime
DATETIMETIMESTAMPappendTimestamp
DATETIME(6)TIMESTAMPappendTimestamp
TIMESTAMPTIMESTAMPappendTimestamp
TIMESTAMP(6)TIMESTAMPappendTimestamp
YEARVARCHARappendVarchar
BIT(n)VARCHARappendVarchar(int)
BOOLEANBOOLEANappendBoolean

Numeric Types

Integer Types

All MySQL integer types map cleanly to DuckDB equivalents:
  • TINYINT → TINYINT (8-bit signed)
  • SMALLINT → SMALLINT (16-bit signed)
  • MEDIUMINT → BIGINT (24-bit promoted to 64-bit)
  • INT → BIGINT (32-bit promoted to 64-bit)
  • BIGINT → BIGINT (64-bit signed)
MEDIUMINT and INT are promoted to BIGINT in DuckDB for consistency and to avoid overflow issues.

Unsigned Integer Handling

INT UNSIGNED maps to BIGINT since DuckDB doesn’t have unsigned types. This provides sufficient range for most use cases. BIGINT UNSIGNED has a known limitation:
BIGINT UNSIGNED Overflow: Values above 9,223,372,036,854,775,807 (BIGINT_MAX) will overflow DuckDB’s signed BIGINT and crash the appender. The maximum MySQL unsigned value 18,446,744,073,709,551,615 (2^64-1) cannot be stored.

Floating Point Types

  • FLOAT → FLOAT (32-bit IEEE 754)
  • DOUBLE → DOUBLE (64-bit IEEE 754)
Floating point values preserve their precision through replication.

Decimal Types

MySQL DECIMAL(p,s) maps to DuckDB’s DECIMAL type:
DECIMAL Precision: MySQL DECIMAL(20,10) maps to DuckDB’s bare DECIMAL type. High-precision values may experience truncation depending on the DuckDB DECIMAL width. Integration tests use assert_contains on the integer portion rather than exact matching.

String Types

Fixed and Variable Length

  • CHAR(n) → VARCHAR
  • VARCHAR(n) → VARCHAR
Both fixed and variable-length character types map to DuckDB’s VARCHAR. Length constraints are not enforced in DuckDB.

Text Types

All MySQL text variants map to DuckDB TEXT:
  • TINYTEXT → TEXT
  • TEXT → TEXT
  • MEDIUMTEXT → TEXT
  • LONGTEXT → TEXT
DuckDB’s TEXT type can handle strings of any length, so all MySQL text variants use the same type.

UTF-8 Support

Full UTF-8 4-byte character support (emoji and special characters) is preserved through replication.

Binary Types

Binary types have limited support:
  • BINARY(n) → BLOB (full sync only)
  • VARBINARY(n) → BLOB (full sync only)
  • TINYBLOB → BLOB (full sync only)
  • BLOB → BLOB (full sync only)
  • MEDIUMBLOB → BLOB (full sync only)
  • LONGBLOB → BLOB (full sync only)
Binary Types & CDC: Binary types (BLOB, BINARY, VARBINARY, TINYBLOB, MEDIUMBLOB, LONGBLOB) and BIT break the INSERT OR REPLACE SQL path used by CDC updates. These types are only tested via the full-sync Appender path. The CDC test table (type_coverage_cdc) deliberately excludes binary and BIT columns.

Special Types

JSON

JSON → JSON (DuckDB native JSON type) JSON columns map to DuckDB’s native JSON type with automatic stringification via JSON.stringify().
-- MySQL
CREATE TABLE products (
  id INT PRIMARY KEY,
  metadata JSON
);

-- DuckDB (after sync)
CREATE TABLE products (
  id BIGINT PRIMARY KEY,
  metadata JSON
);

ENUM

ENUM → VARCHAR ENUM values are stored as VARCHAR strings in DuckDB. The set of allowed values is not enforced.

SET

SET → VARCHAR SET values are stored as comma-separated VARCHAR strings (e.g., 'a,b,c').

BIT

BIT(n) → VARCHAR BIT types are converted to VARCHAR representation of the integer value. Only supported in full sync mode.

Date and Time Types

Date

DATE → DATE Date values are automatically converted to ISO string format during replication.

Time

TIME → TIME
TIME(6) → TIME
Time values with or without fractional seconds are supported.

Datetime and Timestamp

DATETIME → TIMESTAMP
DATETIME(6) → TIMESTAMP
TIMESTAMP → TIMESTAMP
TIMESTAMP(6) → TIMESTAMP
All timestamp types map to DuckDB’s TIMESTAMP with fractional second precision preserved.

Year

YEAR → VARCHAR YEAR type is stored as a VARCHAR string (e.g., '2024').

Unsupported Types

Spatial/Geometry Types

Spatial Types Not Supported: MySQL spatial types (POINT, LINESTRING, POLYGON, GEOMETRY, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION) are not supported.These columns fall through to the VARCHAR default mapping, which stores the raw binary WKB (Well-Known Binary) representation as a string. Tables with spatial columns will sync but the spatial data is not usable for spatial queries in DuckDB.DuckDB has a spatial extension but Duckling does not perform WKB-to-geometry conversion.

Test Coverage

Duckling includes comprehensive integration tests for type fidelity:

Test Tables

TablePurposeColumn Count
type_coverageFull-sync Appender path testing (all types including binary and BIT)27 columns
type_coverage_cdcCDC path testing (non-binary types only)19 columns

Suite 7: Type Fidelity (Full Sync)

Tests every MySQL 8 type through the Appender path with 3 seed rows:
Min/max boundary values for each type:
  • TINYINT: -128
  • INT UNSIGNED: 4,294,967,295
  • DOUBLE: max value
  • CHAR(10): full length
  • TIME: max value
  • TIMESTAMP: fractional seconds
  • SET: combinations
  • BIT(1): 1
  • BIT(8): 255
  • Zeros for all numeric types
  • Empty strings for text/char
  • Zero TIME
  • Epoch timestamps
  • Empty SET
  • BIT(1): 0
  • BIT(8): 0
Every nullable column set to NULL. Validates NULL propagation through the Appender pipeline.

Suite 6: CDC Extension Type Fidelity

Tests non-binary types through CDC INSERT and UPDATE paths: CDC INSERT: Inserts 1 row with diverse types (TINYINT -42, SMALLINT 1000, MEDIUMINT 500000, INT UNSIGNED 3000000000, DOUBLE 2.71828, DECIMAL 12345, CHAR ‘CDC-TEST’, text variants, TIME, YEAR 2024, SET ‘b,d’). Validates 12 column values. CDC UPDATE: Updates 5 columns (TINYINT→127, SMALLINT→32767, DOUBLE→-1.0, CHAR→‘UPDATED’, SET→‘a,b,c’). Validates all 5 updated values.

Test Assertions

SuiteAssertions
Suite 1: Full Sync24
Suite 2: Incremental Insert12
Suite 3: Incremental Update8
Suite 4: Single Table Sync4
Suite 5: Idempotent Re-sync8
Suite 6: CDC Real-Time (+ type ext)35
Suite 7: Type Fidelity64
Total~155

Running the Tests

cd tests/integration
chmod +x run.sh
./run.sh

Implementation References

  • Type mapping logic: packages/server/src/services/sequentialAppenderService.ts
  • DuckDB connection: packages/server/src/database/duckdb.ts
  • Test schema: tests/integration/mysql-init/01-schema.sql
  • Test runner: tests/integration/run.sh

Build docs developers (and LLMs) love