Skip to content

fix(extension): skip MEOS timezone init when no zoneinfo on system (unblocks musl probe)#182

Open
estebanzimanyi wants to merge 6 commits into
MobilityDB:mainfrom
estebanzimanyi:fix/meos-tz-init-resilient
Open

fix(extension): skip MEOS timezone init when no zoneinfo on system (unblocks musl probe)#182
estebanzimanyi wants to merge 6 commits into
MobilityDB:mainfrom
estebanzimanyi:fix/meos-tz-init-resilient

Conversation

@estebanzimanyi
Copy link
Copy Markdown
Member

Summary

Skip the MEOS meos_initialize_timezone("Europe/Brussels") call when /usr/share/zoneinfo isn't present on the system. This unblocks the musl probe (PR #172) without requiring a separate fix to the upstream extension-ci-tools Dockerfile.

Background

meos_initialize_timezone(...) calls into MEOS's pgtz code which opens /usr/share/zoneinfo to load the timezone database. On minimal containers (Alpine/musl, edge-device runtimes) tzdata is not installed by default, so the call surfaces:

could not open directory "/usr/share/zoneinfo": No such file or directory
could not open directory "/usr/share/zoneinfo": No such file or directory
make: *** [Makefile:36: test_release_internal] Error 1

…and the test runner downstream then errors. This was the exact failure mode on the musl probe (#172, linux_amd64_musl row) — MEOS C compiled+linked green, but the runtime timezone init failed.

The fix

Guard the meos_initialize_timezone call with a portable stat + S_IFDIR check on the canonical zoneinfo directory:

struct stat tz_st {};
if (stat("/usr/share/zoneinfo", &tz_st) == 0 && (tz_st.st_mode & S_IFDIR)) {
    meos_initialize_timezone("Europe/Brussels");
}

If zoneinfo isn't present, the extension loads against MEOS's default (UTC) instead of erroring at startup.

Behaviour matrix

Host Pre-fix Post-fix
Linux x86_64 (Ubuntu/manylinux2_28) with tzdata ✅ Brussels TZ ✅ Brussels TZ (unchanged)
Linux arm64 with tzdata ✅ Brussels TZ ✅ Brussels TZ (unchanged)
macOS with tzdata ✅ Brussels TZ ✅ Brussels TZ (unchanged)
musl/Alpine without tzdata ❌ "could not open directory" → tests fail ✅ UTC default; extension loads
Future edge-device runtimes Same failure mode ✅ Resilient

Alternative: upstream Dockerfile fix

The complementary fix is apk add tzdata in extension-ci-tools/docker/linux_amd64_musl/Dockerfile. Both unblock the musl probe; having both gives belt-and-suspenders coverage and lets the extension load on any tzdata-less host (not just the CI image).

The extension-side fix in this PR has the additional benefit that it makes MobilityDuck deployable on edge devices and minimal containers without requiring the operator to install tzdata.

Verification

Linux x86_64 build green (4 polyfills inherited from the substrate stack + 1 TZ-resilient commit):

$ cmake --build build/release --config Release --target mobilityduck_loadable_extension -- -j1
[72/72] Linking CXX shared library extension/mobilityduck/mobilityduck.duckdb_extension

$ ./build/release/duckdb -c "LOAD '...mobilityduck.duckdb_extension'; SELECT asText(TGEOGPOINT(ST_Point(1, 2), to_timestamp(946684800)));"
POINT(1 2)@2000-01-01 01:00:00+01

The Brussels TZ output is preserved on a host with zoneinfo present.

Refs

… PR MobilityDB#161)

Cherry-picked from open PR MobilityDB#161 so this PR's CI compiles against the
vcpkg-installed MEOS, which exposes 'meosType' (pre-consolidation)
not 'MeosType'.  When MobilityDB#161 reaches main, this commit collapses to a
no-op on rebase.
…MobilityDB#136)

Cherry-picked from open PR MobilityDB#136 so this PR's amd64 Linux test phase
goes green before MobilityDB#136 lands.  When MobilityDB#136 reaches main, this rebase
collapses to a no-op.
…en PR MobilityDB#140)

Cherry-picked from open PR MobilityDB#140 so this PR's osx_amd64 / osx_arm64 /
wasm builds compile.  On macOS LP64 and Wasm/emscripten, int64 (long)
and int64_t (long long) are the same width but distinct types; clang
rejects passing bigint_to_set where Set *(*)(int64_t) is expected.
The cast is a no-op on Linux.  When MobilityDB#140 reaches main, this rebase
collapses to a no-op.
…e_ptr<FunctionData> in Copy()

GCC + DuckDB 1.4.4's unique_ptr does not implicitly convert
derived->base, so 'return r;' in BinsBindData::Copy() fails to compile:

  error: could not convert 'r' from 'unique_ptr<duckdb::{anonymous}::BinsBindData,...>'
                                to 'unique_ptr<duckdb::FunctionData,...>'

Use duckdb's unique_ptr_cast helper (from duckdb/common/helper.hpp) to
do the conversion explicitly, matching the canonical pattern used by
DuckDB core (e.g. table_scan.hpp's TableScanBindData::Copy()).  No
behaviour change; the move is exactly what the implicit conversion
would have done if the compiler accepted it.
`meos_initialize_timezone("Europe/Brussels")` calls into MEOS's pgtz
code which opens `/usr/share/zoneinfo` to load the timezone database.
On minimal containers (Alpine/musl, edge-device runtimes) zoneinfo is
not installed by default and the call surfaces:

    could not open directory "/usr/share/zoneinfo": No such file or directory

…which then aborts the test runner downstream (see musl probe PR MobilityDB#172,
linux_amd64_musl row).

Guards the call with a portable `stat` check on the canonical zoneinfo
directory; if not present, the extension loads against MEOS's default
(UTC) instead of erroring at startup.

This is the lightweight extension-side counterpart to the upstream
extension-ci-tools fix (`apk add tzdata` in the linux_amd64_musl
Dockerfile) — both unblock the musl probe.  Either alone is sufficient;
having both gives belt-and-suspenders coverage and lets the extension
load on any tzdata-less host.

Verified locally:
  build/release/extension/mobilityduck/mobilityduck.duckdb_extension links;
  on a host with `/usr/share/zoneinfo` present, behaviour is unchanged
  (Brussels TZ still set, asText output shows `+01` in winter dates).
The stage_icu helper mapped only the Linux uname values, so on the
macOS arm64 test runner uname -m returned "arm64" and the icu
extension was copied to .duckdb/extensions/v1.4.4/arm64 instead of
.../osx_arm64, where DuckDB's autoload looks. The hub fallback is not
reliably resolvable on that runner, so the osx_arm64 Test step failed
to load the extension. Map the OS and architecture to the DuckDB
platform string (linux_amd64, linux_arm64, osx_amd64, osx_arm64) so
the locally built icu is staged at the path autoload expects on every
tested platform; the Linux mapping is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant