You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implements ADR-0064 (full refresh), the connection facts of ADR-0060, and ADR-0068 (parallelism declaration); first live consumer of the #134 mapping and #135 Accept Family modules; test posture per ADR-0066. Part of the SQL Server destination cycle (map #106, sliced from #113).
The first live mode. The connector bridges the sync Destination/DestinationWriter seam (src/connector.rs:290, :356) to async tiberius with a connector-contained current-thread tokio runtime — one runtime and one client per load, nothing async escaping the connector (the #107 research posture). Full refresh is the only mode that bootstraps a table; production tables are owned by their environment, so the write never replaces the table object.
The contract
Session: SQL auth; encryption: required → tiberius default encryption, optional → EncryptionLevel::Off (login encrypted where possible, data traffic per server policy — the production SSMS Encrypt=Optional parity posture); trust_server_certificate honored; a hardcoded 15 s connect timeout so a hang becomes a clean failure; application_name pinned to data-spark. The password is read from the password_env variable at connect time (its presence was validated offline in the Definition phase).
begin(full_refresh): table absent → CREATE TABLE in the created shape (Generate SQL Server DDL and bulk rows from the dataset schema #134); table present → introspect and validate against the Accept Family (Validate existing SQL Server tables against the Accept Family #135, full-refresh rules; violations fail incompatible_destination_table before any write). Then BEGIN TRAN and DELETE FROM [schema].[table] — object-preserving, never drop/rename (a staged sp_rename swap is rejected by ADR-0064: it strips permissions, indexes, triggers, FKs).
commit: terminal COMMIT. Write facts: atomicity: "atomic", strategy: "transactional_delete_insert" (new string, additive under the report contract's version-1 clause). A zero-survivor full refresh commits an empty table — ADR-0056's mirror semantics.
Failure: explicit best-effort ROLLBACK; failures surface as destination_write_failed (or incompatible_destination_table from validation). Every raising site classifies Transience::Terminal in this slice — the transience slice flips the decided sites later (ADR-0067's terminal-first-then-flip path).
Modes: supported_load_modes = full refresh only; append and merge keep declining via unsupported_load_mode_for_destination until their slices widen the list.
Parallelism: parallelism_limit declared 1 for all three modes — declared, not defaulted (ADR-0068); the report keeps stating the effective value beside the connector limit.
Tests (ADR-0066): pure logic ungated; live tests carry #[ignore = "needs SQL Server"], connect with fixed defaults matching the CI container of Run CI and release tests against a live SQL Server with --include-ignored #131, overridable via the DATA_SPARK_TEST_MSSQL_* env family (host, port, user, password), and never start containers themselves. CI proves them via --include-ignored.
Acceptance criteria
Gated live tests:
Bootstrap: full refresh onto an absent table creates the created shape (introspection read-back asserts exact types — BIGINT, FLOAT, BIT, NVARCHAR(MAX), DATETIME2(6), DECIMAL(p,s) — and nullability) and lands the rows; values round-trip exactly (instants UTC-normalized, microsecond precision, i64::MAX, negative decimals, empty string ≠ NULL).
Object preservation: an index created out-of-band on the table survives a second full refresh; rows are replaced.
Zero survivors: an all-rejected source under a permissive threshold commits an empty table with atomic/transactional_delete_insert facts.
Incompatibility: an existing table with a VARCHAR column fails incompatible_destination_table at begin; the target's rows are untouched.
Representability sliver: a >32,767-character utf8 value fails the load as a write failure (never a Rejected Record), the transaction rolls back, and the destination is unchanged.
Implements ADR-0064 (full refresh), the connection facts of ADR-0060, and ADR-0068 (parallelism declaration); first live consumer of the #134 mapping and #135 Accept Family modules; test posture per ADR-0066. Part of the SQL Server destination cycle (map #106, sliced from #113).
Blocked by #131, #132, #135
Context
The first live mode. The connector bridges the sync
Destination/DestinationWriterseam (src/connector.rs:290, :356) to async tiberius with a connector-contained current-thread tokio runtime — one runtime and one client per load, nothing async escaping the connector (the #107 research posture). Full refresh is the only mode that bootstraps a table; production tables are owned by their environment, so the write never replaces the table object.The contract
encryption: required→ tiberius default encryption,optional→EncryptionLevel::Off(login encrypted where possible, data traffic per server policy — the production SSMSEncrypt=Optionalparity posture);trust_server_certificatehonored; a hardcoded 15 s connect timeout so a hang becomes a clean failure;application_namepinned todata-spark. The password is read from thepassword_envvariable at connect time (its presence was validated offline in the Definition phase).CREATE TABLEin the created shape (Generate SQL Server DDL and bulk rows from the dataset schema #134); table present → introspect and validate against the Accept Family (Validate existing SQL Server tables against the Accept Family #135, full-refresh rules; violations failincompatible_destination_tablebefore any write). ThenBEGIN TRANandDELETE FROM [schema].[table]— object-preserving, never drop/rename (a stagedsp_renameswap is rejected by ADR-0064: it strips permissions, indexes, triggers, FKs).bulk_insertper chunk inside the transaction (bulk load inside a user-defined transaction is documented TDS behavior and rolls back with it), rows in table column order via Generate SQL Server DDL and bulk rows from the dataset schema #134.COMMIT. Write facts:atomicity: "atomic",strategy: "transactional_delete_insert"(new string, additive under the report contract's version-1 clause). A zero-survivor full refresh commits an empty table — ADR-0056's mirror semantics.ROLLBACK; failures surface asdestination_write_failed(orincompatible_destination_tablefrom validation). Every raising site classifiesTransience::Terminalin this slice — the transience slice flips the decided sites later (ADR-0067's terminal-first-then-flip path).supported_load_modes= full refresh only; append and merge keep declining viaunsupported_load_mode_for_destinationuntil their slices widen the list.parallelism_limitdeclared 1 for all three modes — declared, not defaulted (ADR-0068); the report keeps stating the effective value beside the connector limit.#[ignore = "needs SQL Server"], connect with fixed defaults matching the CI container of Run CI and release tests against a live SQL Server with --include-ignored #131, overridable via theDATA_SPARK_TEST_MSSQL_*env family (host, port, user, password), and never start containers themselves. CI proves them via--include-ignored.Acceptance criteria
BIGINT,FLOAT,BIT,NVARCHAR(MAX),DATETIME2(6),DECIMAL(p,s)— and nullability) and lands the rows; values round-trip exactly (instants UTC-normalized, microsecond precision,i64::MAX, negative decimals, empty string ≠ NULL).atomic/transactional_delete_insertfacts.VARCHARcolumn failsincompatible_destination_tableat begin; the target's rows are untouched.utf8value fails the load as a write failure (never a Rejected Record), the transaction rolls back, and the destination is unchanged.destination_summaryecho, the atomic facts, andconnector_parallelism_limit: 1; exit codes follow the existing contract.cargo test --lockedpasses with the live tests visiblyignored; CI (with the Run CI and release tests against a live SQL Server with --include-ignored #131 container) runs them for real.CHANGELOG.mdUnreleased entry: the sqlserver destination lands with full-refresh support, namingincompatible_destination_tablein prose.