pdo_duckdb 0.9.0: DuckDB 2.0 through PDO, and the upgrade traps (storage version 69, silently empty commits, $1_0)
pdo_duckdb is my PDO driver for DuckDB, the in-process analytical database. 0.9.0 bundles DuckDB 2.0.0 GA in every prebuilt binary. The last version I posted here was 0.5.0, so this covers 0.6.0 through 0.9.0, starting with what changes for your code when you move to 2.0.
What breaks on 2.0
- New files are unreadable by 1.5. 2.0 writes storage version 69, and 1.5 reads only 64 to 68 (IO Error: Trying to read a database file with version number 69). Existing 1.5 files keep their format. If a 1.5 process shares a new file, open it with new PDO('duckdb:/data/shared.duckdb;storage_compatibility_version=v1.5.6').
- Any failed statement aborts the transaction. Inside beginTransaction(), a parser or catalog error now aborts it too, and every later statement fails. On either version, commit() on an aborted transaction returns true and keeps nothing, so call rollBack() after a failure or set default_transaction_invalidation_policy=SYNTACTIC_ERRORS_DO_NOT_INVALIDATE.
- Integer division by zero throws. 1 // 0 raises instead of returning NULL. Wrap it in TRY(...) or set error_on_division_by_zero=false.
- x -> x + 1 lambdas are rejected. Write lambda x: x + 1, which also works on 1.5.
- The PEG parser is the default, and it numbers parameters differently: $1_0 is parameter 10 under PEG and parameter 1 under the legacy parser. ? and :name are portable.
Source builds still work against DuckDB 1.5.3 and newer. configure detects 2.0 from duckdb_v2.h, since the 2.0 headers still report C API 1.5.6.
New in 0.9.0
- PDO::DUCKDB_ATTR_NATIVE_STRUCTURES, an opt-in that fetches LIST, ARRAY, STRUCT, MAP, UNION, JSON and VARIANT as lossless PHP values instead of canonical strings.
- VARIANT fetching, top-level and nested, and Appender input for it from arrays and objects.
- Two PDO connections to the same file could lose writes and see stale reads. Equivalent paths now share one DuckDB instance, and transactions stay per connection.
- Prebuilts for PHP 8.2 to 8.6 (8.6 as development builds) on Linux glibc and musl, macOS arm64, and Windows x64. They need PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12+, the October security releases; older patches build from source.
Security fixes since 0.5.0
0.8.0 carries the fixes from a security scan of the driver this month. An unclosed Appender in a reference cycle could read its PDO connection after gc_collect_cycles() or shutdown freed it. Hitting memory_limit during column setup could leave uninitialized type handles that were destroyed later. Earlier, 0.6.0 and 0.7.0 rejected DECIMAL types outside DuckDB's width and scale limits, a falsy force_mbedtls_unsafe that crashed the process, LOB binds over 64 MB, and Appender rows nested deeper than 128 levels.
pie install iliaal/pdo_duckdb
iliaal/pdo_duckdb
If you run DuckDB from PHP, I'd like to hear which 2.0 change hits your code first.
4 points
Mentions
pdo_duckdb 0.9.0: DuckDB 2.0 through PDO, and the upgrade traps (storage version 69, silently empty commits, $1_0) pdo_duckdb is my PDO driver for DuckDB, the in-process analytical database. 0.9.0 bundles DuckDB 2.0.0 GA in every prebuilt binary. The last version I posted here was 0.5.0, so this covers 0.6.0 through 0.9.0, starting with what changes for your code when you move to 2.0. What breaks on 2.0 - New files are unreadable by 1.5. 2.0 writes storage version 69, and 1.5 reads only 64 to 68 (IO Error: Trying to read a database file with version number 69). Existing 1.5 files keep their format. If a 1.5 process shares a new file, open it with new PDO('duckdb:/data/shared.duckdb;storage_compatibility_version=v1.5.6'). - Any failed statement aborts the transaction. Inside beginTransaction(), a parser or catalog error now aborts it too, and every later statement fails. On either version, commit() on an aborted transaction returns true and keeps nothing, so call rollBack() after a failure or set default_transaction_invalidation_policy=SYNTACTIC_ERRORS_DO_NOT_INVALIDATE. - Integer division by zero throws. 1 // 0 raises instead of returning NULL. Wrap it in TRY(...) or set error_on_division_by_zero=false. - x -> x + 1 lambdas are rejected. Write lambda x: x + 1, which also works on 1.5. - The PEG parser is the default, and it numbers parameters differently: $1_0 is parameter 10 under PEG and parameter 1 under the legacy parser. ? and :name are portable. Source builds still work against DuckDB 1.5.3 and newer. configure detects 2.0 from duckdb_v2.h, since the 2.0 headers still report C API 1.5.6. New in 0.9.0 - PDO::DUCKDB_ATTR_NATIVE_STRUCTURES, an opt-in that fetches LIST, ARRAY, STRUCT, MAP, UNION, JSON and VARIANT as lossless PHP values instead of canonical strings. - VARIANT fetching, top-level and nested, and Appender input for it from arrays and objects. - Two PDO connections to the same file could lose writes and see stale reads. Equivalent paths now share one DuckDB instance, and transactions stay per connection. - Prebuilts for PHP 8.2 to 8.6 (8.6 as development builds) on Linux glibc and musl, macOS arm64, and Windows x64. They need PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12+, the October security releases; older patches build from source. Security fixes since 0.5.0 0.8.0 carries the fixes from a security scan of the driver this month. An unclosed Appender in a reference cycle could read its PDO connection after gc_collect_cycles() or shutdown freed it. Hitting memory_limit during column setup could leave uninitialized type handles that were destroyed later. Earlier, 0.6.0 and 0.7.0 rejected DECIMAL types outside DuckDB's width and scale limits, a falsy force_mbedtls_unsafe that crashed the process, LOB binds over 64 MB, and Appender rows nested deeper than 128 levels. pie install iliaal/pdo_duckdb iliaal/pdo_duckdb If you run DuckDB from PHP, I'd like to hear which 2.0 change hits your code first.