Repository navigation
Conversation
Build sqlload and sqlload-cli wheels for Windows x86_64 (MSVC) and macOS x86_64 (macos-15-intel), and test Windows in CI. - librdkafka builds with CMake on Windows, where its configure script and make are missing. - Local paths: drive paths (C:\data), UNC shares (\\server\share), \\?\ paths and file:///C:/ and file://server/share URLs are local folders on Windows; Unix paths are unchanged. - A postgres_cdc replication session's relay on Windows is a 127.0.0.1 port, since the replication client cannot reach a socket file there. It relays only the connection whose startup message carries a random per-session secret, drops every other connection before a byte reaches the server, gives each 5 seconds, and never forwards the secret. - Verify gains a Windows job: unit tests, then the executable end to end over drive paths, a UNC share, psqlODBC against the runner's Postgres, and a postgres_cdc load streamed through the relay. - Publish builds and smoke-tests every wheel on pull requests that change packaging, and publishes only when dispatched.
…nto session_relay A relay refusal no longer disables tokio::select!'s join arm, which could leave an admitted client unread until the relay's deadline when two refusals finished together; a test now opens refused connections first. The Unix socket-folder and Windows loopback relays live in session_relay. On Windows, folder names under a filesystem connection match ignoring case, and file://localhost/C:/ names the drive. Publish's PR trigger also covers the workspace manifest and lockfile.
russh reaches ssh-agent through SSH_AUTH_SOCK's Unix socket only on Unix; on Windows it now opens the pipe SSH_AUTH_SOCK names, or else the OpenSSH agent service's. The test kit sets Unix key-file permissions only on Unix.
…and isn't tested there
Deploying sqlload with
|
| Latest commit: |
3642977
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6186b065.sqlload.pages.dev |
| Branch Preview URL: | https://wip-chi-1235-windows.sqlload.pages.dev |
…lds; releases never cancel
… folder-swap gap Windows has A Windows temp path in a TOML basic string reads \U as a unicode escape, so the command tests now quote the root with single quotes. Windows can't swap two folders in one rename, so a reader may briefly see no folder there, as the files target docs now say.
…on a cp1252 console
…er's A Windows main thread, sqlload.exe's or python.exe's, has 1 MB of stack, which a debug build's copy into a files target outgrew (0xC00000FD, reproduced on Linux with ulimit -s 1024). Every command now runs on a scoped thread with a Linux main thread's default 8 MiB, whoever calls it.
…ested wheel A table function yields rows and then blocks; the load gets a real Ctrl-C (SIGINT, or a console Ctrl-C event on Windows) and must end at once as the native executable does, with no traceback and nothing committed, and the next load must write every row once. Commands now run on a thread of their own rather than Python's main thread, so this checks Ctrl-C still reaches them.
object_store keeps a local store's root as a file:// URL, and the url crate reads
file://localhost/share/... back as a drive path, so every file on a \\localhost\ share failed to
convert ("Unable to convert URL ... to filesystem path"). The store now opens such a share as
\\127.0.0.1\share, the same server; what SQLLoad prints keeps the path as written. The Windows
end-to-end checks also write through the machine's own name, as a share on another server is named.
…ve console does, with a control The Windows wheel's Ctrl-C check found the load still running 15 s after the event. A plain load installs no Ctrl-C handler of its own, and a Windows child inherits its parent's "ignore Ctrl-C" flag, which the runner's processes may carry. Each interrupted child now clears that flag first, as a process in an interactive console has it clear. Before the load, a plain Python process with Ctrl-C's default action gets the same event: once as the runner starts it (printed) and once with the flag cleared (it must end), so a failing load is the load's fault, not the check's.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CHI-1235. Adds Windows x86_64 and macOS x86_64 (Intel) wheels for
sqlloadandsqlload-cli, and tests Windows in CI.Why Windows was never built
It was left out, not decided against:
publish.ymlhas built the same three wheels since the first commit, and no commit ever added or removed Windows. Since then, two things stopped the crate building there:configurescript andmake, which MSVC doesn't have. On Windows it now builds with CMake (rdkafka/cmake-build, Windows targets only).cfgguard. See below.Changes
Wheels:
windows-latestandmacos-15-intelrows.macos-15-intelis GitHub's last Intel image, available until August 2027. macOS wheels target 11.0, which was already the arm64 floor. Vendored OpenSSL builds with Strawberry Perl on Windows. The smoke test now installs and runs both wheels on every platform.Publish on pull requests: a PR that changes packaging (this workflow, the tag checks, the pyprojects, the workspace and crate manifests,
Cargo.lock) builds and smoke-tests every wheel and the sdists, and publishes nothing. PyPI and crates.io run only on a dispatched release.Windows paths: these are now local folders on Windows: drive paths (
C:\data), UNC shares (\\server\share\x),\\?\and\\?\UNC\paths,file:///C:/x,file://localhost/C:/xandfile://server/share/x. Unix parsing is unchanged. Path matching under a filesystem connection compares roots too, soD:\lakeis not underC:\lake. On Windows, roots and folder names match ignoring case, as NTFS and SMB do. A share onlocalhost(\\localhost\share) opens through\\127.0.0.1\share, the same server. object_store keeps a local root as afile://URL, and the url crate readsfile://localhost/share/...back as a drive path. Without this, every file on such a share failed with "Unable to convert URL". The Windows end-to-end job found it. It now writes to the share both as\\localhost\…and through the runner's own name, as a share on another server is named. SQLLoad's own messages keep the path as written, but object_store's error text, which SQLLoad includes, shows\\127.0.0.1. Windows keeps SMB credentials per server name, so access that depends on anet useorcmdkeyentry forlocalhostalone may be refused through127.0.0.1; such a share didn't work through the store at all before.\\.\UNC\localhost\…roots are still unsupported, as before. A read-only check of this fix covered other servers,\\?\UNC\andfile://forms,localhost./IPv6/127.0.0.1spellings and Unix, and found no blockers.ssh-agent on Windows: russh reaches the agent through
SSH_AUTH_SOCK's Unix socket only on Unix, sossh_tunneldidn't compile for Windows. There it now opens the pipeSSH_AUTH_SOCKnames, or else OpenSSH's agent service pipe (\\.\pipe\openssh-ssh-agent).Verify, new
Windowsjob (windows-2025): runs the unit tests, then runs the executable end to end (.github/scripts/windows_e2e.py):\\localhost\sqlload-e2e), read back throughfile://localhost/...and a\\?\UNC\path;postgres_cdcload streaming through the Windows relay.The aggregate
Verifycheck now includes this job.Publish concurrency: a new push to a pull request cancels that PR's older Publish run. A dispatched release run has a group of its own, so releases never cancel each other.
Commands run on an 8 MiB thread: the Windows end-to-end
copyonto the UNC share crashed with a stack overflow (0xC00000FD), because a Windows main thread has 1 MB of stack against 8 MB on Linux. Making the futures smaller didn't fix it (Box::pinwas tried).run_args_with_hostnow runs each command on a scoped thread namedsqlload-commandwith 8 MiB of stack, the same for the executable and the wheel. A panic on that thread is resumed in the caller. Reproduced on Linux withulimit -s 1024before the fix; it passes after.The Postgres replication relay on Windows
Why there is a relay at all: pgwire-replication dials
host:portitself, so its own TLS can't run through SQLLoad's SSH tunnel. The relay lets the TLS code every other SQLLoad Postgres connection uses serve both direct and tunnelled replication sessions.Both relays now live in a
session_relaymodule, andrelay_tlscallsrelay_session. On Linux and macOS the relay is unchanged: a socket file in a 0700 folder. On Windows, pgwire-replication can only dial TCP (its socket path iscfg(unix)), and it can't take a stream we open ourselves. So the relay listens on an ephemeral127.0.0.1port:application_name = sqlload-<32 random bytes, hex>, made fresh for each session. It compares in constant time and rewrites the name tosqlloadbefore forwarding.select!arm that collects admissions. The review found that two refusals finishing together could leave the admitted client unread until the 30-second deadline.Secret, whoseDebugis redacted. It is never forwarded to the server.select!arm); and wrong-secret, no-secret, oversize, SSLRequest, protocol 2.0 and no-application-name connections. In each, the server gets zero bytes before the client, every earlier connection is closed unanswered, the client is relayed within 2.5 seconds, the forwarded StartupMessage carriessqlloadand not the secret, bytes pipe both ways, and a later connection is refused.ReplicationClient::connect_on_stream/connect_gated_on_streamin pgwire-replication would remove the relay on every OS. The patch is written and passes upstream's 142 unit tests, clippy and fmt. The upstream PR isn't open yet: opening a PR on an outside repository is Kevin's decision, and it's pending. The patch, its base commit and a draft PR are on CHI-1242, the ticket for removing the relay. The upstream PR will be linked here once it's opened.Ctrl-C during a Python-source load
Commands no longer run on Python's main thread, and Python only runs signal handlers there. Ctrl-C is unaffected, because
sqlload._clisets SIGINT to its default action before entering native code. Ctrl-C then ends the process as it ends the executable, from whichever thread is running. Table functions already ran on tokio's blocking workers..github/scripts/interrupt_python_load.pychecks this. It runs in the wheel smoke test on all five platforms, so the release run checks it on the wheels it publishes:STATUS_CONTROL_C_EXITon Windows), print no traceback, and commit nothing.On Linux it passes: the load exits with -2 at once and nothing is committed. As a control, removing the SIG_DFL line from
_cli.pymakes it fail ("still running 15 s after Ctrl-C"). That is the regression it guards against. Exit code and partial-commit behaviour are the same as before this PR, because the mechanism (SIG_DFL in_cli.py) is unchanged. The Windows result is in this PR's Publish run.Checks run locally (Linux)
cargo test --workspace --lib --features sqlload/odbc: 259 passed.make check-ciconfigurations: clean.cargo xwin checkforx86_64-pc-windows-msvc(lib, unit tests and binary, without DuckDB): clean. The Windows CI job runs the tests there.