Commits on Source 24

  • Toni Spets's avatar
    Support more underscore keys in DSN · 5831f4be
    Toni Spets authored and Ian Chechin's avatar Ian Chechin committed
    For improved DSN compatibility, the following keys have been added:
    
        _foreign_keys | _fk
        _busy_timeout | _timeout
        _journal_mode | _journal
        _synchronous | _sync
        _auto_vacuum | _vacuum
        _query_only
    
    Their values are passed as-is to exec for their respective PRAGMAs and not
    validated in any way. The compatibility here is intended when switching
    between modernc.org/sqlite and mattn/go-sqlite3, where it is handy to have
    higher DSN compatibility and to avoid dangerous mistakes like not having
    foreign keys enabled.
    5831f4be
  • Ian Chechin's avatar
    sqlite: document mattn-compat DSN pragma keys and test them together · 97841221
    Ian Chechin authored
    Follow-up to the DSN shorthand keys carried over from !73: document
    _busy_timeout/_fk/_journal/_sync/_vacuum/_query_only in the driver DSN
    reference, note the fixed apply order (busy_timeout first, query_only last)
    at the query_only call site, and add a combined-DSN test asserting the keys
    coexist in a single DSN regardless of the order they appear in it.
    97841221
  • Ian Chechin's avatar
    sqlite: validate mattn-compat DSN keys and fix auto_vacuum apply order · 266b979e
    Ian Chechin authored
    Addresses the !134 review:
    
    - Apply _auto_vacuum before the _pragma list and the other shorthand keys.
      auto_vacuum only takes effect while the database is new; a _journal_mode
      change materialises page 1 and locks it in, so the previous order made
      _journal_mode=wal&_auto_vacuum=1 silently resolve to auto_vacuum=0. The
      "Test combined DSN" case now includes _auto_vacuum and asserts it reads
      back as 1, proving the fixed order.
    - Validate every shorthand value against the set github.com/mattn/go-sqlite3
      accepts and return an error on anything else, instead of silently ignoring
      it, so a _synchronous or _foreign_keys typo no longer downgrades durability
      or drops enforcement. This also removes the DSN-injection surface these keys
      had, since a value is now either a known token or an error.
    - When a key and its alias are both present, the alias wins, matching mattn
      (_foreign_keys=off&_fk=on -> on).
    - Document the apply order, precedence, accepted values, and that only _pragma
      values are executed verbatim and must be trusted.
    - CHANGELOG entry for #134.
    266b979e
  • cznic's avatar
    Merge branch 'dsn-compat-keys' into 'master' · b31f5212
    cznic authored
    Support more underscore keys in DSN (continues !73)
    
    See merge request !134
    
    Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
    b31f5212
  • cznic's avatar
    CHANGELOG.md: correct the !134 DSN shorthand-key entry · d7210fc8
    cznic authored
    The v1.55.0 entry said the new mattn-compatible keys were "parsed but had
    no effect in prior releases". They were not parsed at all; applyQueryParams
    never looked at them. It also described an unrecognized value as failing
    "instead of being silently ignored", a contrast against an unreleased
    iteration of !134 rather than against v1.54.0, which would read to a user
    upgrading as though their DSN had previously been tolerated and ignored.
    
    Restate both breaks against the last released version: keys that were
    ignored now take effect (with the consequence spelled out rather than just
    the key named), and a value outside the accepted set now fails the
    connection where the same DSN previously opened successfully - e.g. a
    duration-style _busy_timeout=5s, which is not the integer that key
    requires. The latter was missing entirely and is the sharper of the two.
    
    Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
    d7210fc8
  • cznic's avatar
    sqlite: select DSN shorthand aliases by presence, matching mattn (!134 follow-up) · 63a57e47
    cznic authored
    dsnPick treated an empty value as absent, so "_foreign_keys=on&_fk=" fell
    back to the primary key and enabled foreign keys. mattn/go-sqlite3 selects
    between a key and its alias by presence alone and then reads that key's
    value, so the empty alias wins and suppresses the PRAGMA entirely.
    
    Match that: pick on presence, return the selected key's value as-is. An
    empty value still skips the PRAGMA at the call sites, and skips validation
    with it, so an empty shorthand is not an error.
    
    Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
    63a57e47
  • cznic's avatar
    sqlite: validate all DSN parameters before applying any of them · 0895392f
    cznic authored
    applyQueryParams validated each parameter as it reached it, so a DSN whose
    last parameter was bad still executed every PRAGMA ahead of it before
    failing. PRAGMA journal_mode and auto_vacuum are persistent changes to the
    database file, so
    
    	file:x.db?_journal_mode=wal&_synchronous=bogus
    
    failed the connection and left x.db converted to WAL regardless. A failed
    Open must not change the database.
    
    Split the function into a validation phase and an apply phase: everything
    checkable is rejected before the first c.exec. Assignments to c stay in the
    validation phase, since newConn closes and discards the connection when this
    returns an error and they cannot outlive the failure. The documented apply
    order is unchanged and still covered by the combined-DSN test.
    
    This predates the !134 shorthand keys - master already behaved this way for
    _pragma combined with a late-rejected _txlock, which is why the new test
    covers that case too. _pragma remains the o...
    0895392f
  • cznic's avatar
    CHANGELOG.md: document the DSN validation-order change · cfb97341
    cznic authored
    Adds a v1.55.0 entry for validating every DSN parameter before applying any
    of them. It gets its own bullet rather than folding into the !134 paragraph
    because it changes behavior for parameters that have shipped for years -
    _txlock, _timezone, _time_format, _time_integer_format, _inttotime and
    _texttotime - so it concerns readers who never touch the new mattn-compatible
    keys.
    
    The alias-selection fix is folded into the !134 paragraph instead. v1.55.0 is
    not tagged, so no release ever shipped the fallback behavior and describing it
    as a fix would document a bug nobody could have hit.
    
    Also corrects that paragraph's closing claim that "all other existing
    parameters are unchanged", which the validation-order change made false: those
    parameters are affected in when they are validated, though not in what they
    accept or what they mean.
    
    Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
    cfb97341
  • cznic's avatar
    sqlite: add NewConnector, a driver.Connector for sql.OpenDB · 2c7e3eb3
    cznic authored
    database/sql offers no way to reach a registered driver: sql.Drivers returns
    names only and there is no sql.Driver(name). The single route from the
    "sqlite" name back to the driver value is (*sql.DB).Driver(), which is why
    callers who need it resort to
    
    	db, _ := sql.Open("sqlite", "")
    	drv := db.Driver()
    	db.Close()
    
    That opens nothing - it works only because sql.Open does not connect and
    *Driver does not implement driver.DriverContext. Both are properties this
    package could change without noticing it had broken anyone.
    
    Callers want the driver in order to interpose on the physical connections
    database/sql opens: tracing, metrics, connection-scoped setup. Handing out
    the driver alone would not be enough, because the only way to get a wrapper
    into a *sql.DB through sql.Open is sql.Register, which is process-global,
    panics on a name it has already seen and cannot be undone - so a library has
    to invent a unique name per configuration. TestConnectionHook in all_test.go
    is an in-tree instance of that workaround. sql.OpenDB takes a connector
    directly and registers nothing, so a Connector answers both halves.
    
    Connect goes through d.Open rather than newConn, so the connections carry
    every function, collation, connection hook and vtab module registered on the
    package-level driver. A caller-constructed &sqlite.Driver{} carries none of
    them: the fields are unexported, so it silently yields connections missing
    all of it. The 2022 Connector prototype on danp-embed called newConn and had
    exactly that bug.
    
    Deliberately not done:
    
      - No accessor for the package-level driver. driver.Connector requires a
        Driver() method, so the singleton stays reachable, but as the
        driver.Driver interface - one method - and only through a type assertion
        godoc gives no hint of. Nothing returns *sqlite.Driver.
    
      - No OpenConnector on *Driver. Implementing driver.DriverContext would make
        sql.Open eager and move where DSN errors surface for every existing user.
        The sql.Open path is untouched.
    
      - No eager validation of parameter values. That validation is interleaved
        with assignments to *conn in applyQueryParams, and separating it is a
        larger change than this feature warrants. NewConnector checks the query
        string's syntax alone and documents that it does.
    
    NewConnector returns the driver.Connector interface rather than a concrete
    type, keeping the added surface to one symbol. That does not foreclose the
    fs.FS/VFS-lifecycle idea from the danp-embed prototype: database/sql
    discovers an optional Close on the connector by type assertion.
    
    Resolves #253.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    2c7e3eb3
  • cznic's avatar
    sqlite: document that a constructed Driver is not the registered one · e7a39d2d
    cznic authored
    Driver has been exported since 65f6d7e4 (2017), where "Make sqlite public"
    renamed the unexported sqlite type as part of publishing the package. The
    struct then held a connection counter and a mutex, so constructing one cost
    nothing and lost nothing. a9227519 (2022) moved the function and collation
    registries onto it and introduced the package-level instance, which is when
    a constructed Driver started silently lacking things; 14082cad (2023) added
    (*Driver).RegisterConnectionHook, which is only meaningful on an instance the
    caller builds, and so made the export load-bearing.
    
    The result is a type that is legitimately constructible for the private-hook
    pattern yet carries none of what the package-level Register* functions
    install. This documents that on the type and on the method, including the
    consequence easiest to miss: a registered function replaces a SQLite built-in
    of the same name, so a constructed Driver can evaluate upper(x) or date(x)
    differently from a connection opened through sql.Open.
    
    The half-global virtual table module behavior is documented as it stands
    rather than changed. registerModules reads the package-level driver, so
    modules do reach a constructed Driver while functions and collations do not.
    Making that consistent breaks somebody in either direction - inheriting
    silently changes query results for anyone whose registration shadows a
    built-in, isolating turns a working CREATE VIRTUAL TABLE into "no such
    module" - so it wants an issue of its own rather than a doc commit.
    
    No behavior changes.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    e7a39d2d
  • cznic's avatar
    sqlite: validate the connector dsn with getVFSName, not a bare ParseQuery · 581eb450
    cznic authored
    NewConnector parsed the query string itself to reject a malformed dsn early.
    getVFSName is what newConn calls for the same purpose, and it does strictly
    more: the same url.ParseQuery, plus a check for conflicting vfs parameters.
    Calling it instead drops an import, removes the repeated parse, and keeps what
    NewConnector rejects aligned with what opening a connection rejects by
    construction rather than by matching two call sites by hand.
    
    The eager contract widens accordingly: "file:x?vfs=a&vfs=b" is now reported by
    NewConnector rather than by the first Connect. It was already an error either
    way, so no dsn changes from accepted to rejected. Everything a connection must
    exist to check - unknown parameters, out-of-range values - is still reported by
    Connect, as documented.
    
    v1.56.0 is not tagged, so no release shipped the narrower behavior.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    581eb450
  • cznic's avatar
    lib, vec: re-vendor, bump libc to v1.74.4, sweep the docs · cc920f9b
    cznic authored
    Re-vendor the transpiled sources from ../libsqlite3 and ../libsqlite_vec.
    SQLite stays at 3.53.3; what changes is that the amalgamation now carries
    libsqlite3's sqlite_superjournal.patch, fixing an upstream 3.53.3
    data-corruption bug in journal rollback. After a crash during the commit of a
    multi-database (ATTACH) transaction the super-journal name and its checksum
    can be left zeroed while the name length and the trailing magic survive; the
    checksum is a plain byte sum, so an all-zero name still validates,
    readSuperJournal() hands back a non-NULL pointer to an empty string, and
    pager_playback() deletes the hot journal without replaying it. All 19 targets
    carry the patch; master had it on none.
    
    Verified by expanding both the old and the new trees and diffing per target:
    17 of 19 targets differ by exactly that one line. linux/s390x additionally
    picks up modernc.org/cc/v4 v4.29.1's MSB-first big-endian bit-field
    allocation, it being this module's onl...
    cc920f9b
  • wsman's avatar
    sqlite: expose defensive mode DSN option · 9e955072
    wsman authored and cznic's avatar cznic committed
    9e955072
  • cznic's avatar
    sqlite: review follow-ups for the _defensive DSN option · 1fb71c49
    cznic authored
    Documentation, one new validation rule, and test coverage on top of wsman's
    GitHub PR #6. No change to what _defensive itself does.
    
    conn.go: the comment above the db_config calls had been generalized to
    "connection-level sqlite3_db_config options are applied before
    applyQueryParams because the SQLite contract requires
    sqlite3_db_config(SQLITE_DBCONFIG_DQS_*) to be set before any statement is
    prepared". That contract is DQS-specific and does not extend to DEFENSIVE,
    which may be toggled at any point in a connection's life; defensive goes
    first because the PRAGMAs that follow must run under the restriction, which
    is a choice, not an API requirement. Restore the DQS comment verbatim on the
    DQS call and give _defensive its own rationale.
    
    sqlite.go: reject _defensive=1 together with _journal_mode=OFF (or
    _journal=OFF). SQLite turns PRAGMA journal_mode=OFF into a no-op that still
    reports success under defensive mode, so the combination previously opened ...
    1fb71c49
  • cznic's avatar
    all_test: tolerate a cgo-less toolchain in the recursive -race check · 198be3c2
    cznic authored
    TestConcurrentGoroutines re-invokes itself under -race and treats anything
    the recursive run prints other than two known "cannot run here" messages as a
    failure. With CGO_ENABLED=0 the go tool refuses with "-race requires cgo;
    enable cgo by setting CGO_ENABLED=1", which matched neither, so the whole
    suite failed on an environment where the check simply cannot run -- and a
    CGo-free driver is a natural thing to build and test with cgo disabled.
    Accept that message alongside the existing two and skip, as the test already
    does for a toolchain without race support and for an unsupported VMA range.
    Nothing changes when cgo is available: the recursive -race run still executes
    and still has to pass.
    
    Found while reviewing GitHub PR #6, whose author hit it in a CGO_ENABLED=0
    lane; unrelated to that change.
    198be3c2
  • cznic's avatar
    GOVERNANCE.md: add Ian Chechin as maintainer · 69cd3ca1
    cznic authored
    Deln0r has had Maintainer rights on the GitLab project since 2026-06-09.
    The file has named only me since it was added in February and predates
    that grant.
    
    Split out of !135, where the hunk was proposed alongside a code change.
    69cd3ca1
  • cznic's avatar
    licensing: ship the sqlite-vec MIT notice, normalize the license names · 15ca5030
    cznic authored
    vec/ has carried the transpiled sqlite-vec sources since v1.47.0, but the
    module shipped only its own BSD-3-Clause LICENSE and the public-domain SQLite
    notice. sqlite-vec is Copyright (c) 2024 Alex Garcia and dual-licensed
    Apache-2.0 OR MIT; modernc.org/libsqlite_vec's generator elects MIT, whose
    terms require the copyright and permission notice to accompany substantial
    portions of the software. 2.8 MB of transpiled vec/ is a substantial portion.
    Attribution was never absent -- vec's package documentation names the
    extension, pins v0.1.9 and links upstream -- but the license text was.
    
    LICENSE-SQLITE_VEC: the notice, byte-identical to LICENSE-MIT in the upstream
    v0.1.9 archive and to the file libsqlite_vec extracts it into.
    
    vendor_libs/main.go: the omission was mechanical -- the tool copied the
    per-target transpiles and nothing else, so a plain cp of the notice would have
    survived only until the next `make vendor`. Copy it alongside the sources it
    belongs to, and treat a missing source as fatal: shipping the code without the
    notice is worse than not vendoring at all.
    
    SQLITE-LICENSE -> LICENSE-SQLITE, contents unchanged. This matches the new file
    beside it and the LICENSE-<upstream> convention the rest of the modernc.org
    repositories follow, but it is not only cosmetic. `go mod vendor` picks the
    metadata files it copies into a downstream vendor/ tree by matching each name
    against a fixed prefix list (cmd/go/internal/modcmd/vendor.go, metaPrefixes)
    that includes LICENSE, so a name merely ending in LICENSE was never propagated.
    Both notices now reach vendored builds, which is where the MIT terms on vec/
    keep applying. Direct links to the old path will break.
    
    vec/patches.go: a License section on the package documentation, so an importer
    of vec sees on pkg.go.dev that this package is under a different license from
    the rest of the module.
    
    Found by an SBOM audit of the published module.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    15ca5030
  • cznic's avatar
    vendor_libs: handle a deduplicated libsqlite3/libsqlite_vec checkout · 50ee6dd1
    cznic authored
    The vendoring reads one full per-target file at a time from ../libsqlite3 and
    ../libsqlite_vec, which assumes those checkouts ship expanded. They do today,
    but either may adopt the deduplicated layout that modernc.org/wa2c already ships
    (modernc.org/builder's NW autogen; see NW_GENERALIZATION_HANDOFF.md there) — and
    then those per-target files hold only each target's residue, so vendoring them
    would silently drop most of the package.
    
    Detect it instead of remembering it later. srcDir applies undup's own rule
    (base.go or base_g_*.go present means folded) and:
    
      - returns an expanded checkout as is: no copy, no subprocess, exactly the path
        this tool has always taken;
      - copies a deduplicated one to a temp directory and expands it THERE, never in
        place — expanding the sibling would leave that checkout dirty and tempt a
        "restore" that discards whatever else is uncommitted in it. go.mod and go.sum
        travel with the copy be...
    50ee6dd1
  • cznic's avatar
    all_test: drop a trailing space gofmt flags · 224fef61
    cznic authored
    TestDBPageVtab's comment about -DSQLITE_ENABLE_DBPAGE_VTAB carried a trailing
    space, which made all_test.go the one hand-written file in the tree that
    gofmt -l reports. Comment text only; nothing else changes.
    
    Noticed by Ian Chechin while preparing GitLab merge request #135, which does
    not touch this file.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    224fef61
  • cznic's avatar
    all_test: make TestConnectionHook survive -count>1 · 15039fd3
    cznic authored
    The test registered its driver under the fixed name "sqlite_conn_hook_test".
    sql.Register panics on a name it has already seen and offers no way to undo a
    registration, so the second iteration of go test -count=2 took the whole test
    binary down with "sql: Register called twice for driver
    sqlite_conn_hook_test" -- not a failure of the code under test, and it hid
    whatever the remaining iterations would have found.
    
    Derive the name from an atomic counter instead, so each invocation registers
    its own driver, and close the sql.DB the test opens while here: it was leaked
    once per iteration.
    
    Nothing changes for a single run. Ian Chechin's driver_register_test.go in
    GitLab merge request #135 solves the same problem with a uniqueDriverName
    helper; the two can be folded together once that lands.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    15039fd3
  • Ian Chechin's avatar
    sqlite: let a caller-constructed Driver register its own functions, collations and modules · 20e2e17e
    Ian Chechin authored
    Driver holds four categories of registration state but only connection
    hooks could be put on a constructed one. Functions and collations were
    reachable through the package-level API alone, and modules through the
    package-level driver only, so a constructed Driver was half-built: its
    modules field was written and read through the package-level instance,
    making it process-global state wearing a per-instance field.
    
    This is the additive half of #254, with one narrow, loud exception
    spelled out below:
    
      - registerFunction and registerCollation become methods on *Driver.
        The package-level RegisterFunction, RegisterScalarFunction,
        RegisterDeterministicScalarFunction and RegisterCollationUtf8 keep
        targeting the package-level driver, spelled explicitly now rather
        than by relying on the receiver named d shadowing the package
        variable of the same name. newDriver is renamed defaultDriver,
        since it read...
    20e2e17e
  • Ian Chechin's avatar
    9ed2aad5
  • cznic's avatar
    Merge branch 'driver-registration' into 'master' · 47d0960a
    cznic authored
    sqlite: let a caller-constructed Driver register its own functions, collations and modules
    
    See merge request !135
    47d0960a
  • cznic's avatar
    doc.go, CHANGELOG.md: promote freebsd/386, freebsd/arm and netbsd/amd64 · 6e86ac4a
    cznic authored
    All three shipped as experimental in v1.53.0 and were deliberately left out
    of the supported platforms table until they had accumulated some real-world
    exposure. That period has elapsed: they have been in the builder matrix and
    in build_all_targets since, they pass on this release's commit alongside the
    seventeen platforms already listed, and no open issue reports a defect in any
    of them. The table therefore listed seventeen entries while the module
    shipped, cross-built and tested twenty; it now lists all twenty.
    
    Also set the v1.57.0 CHANGELOG date to the release date, and drop a stale
    claim in lib/hooks_linux_arm64.go that this module is "stuck on libc@v1.55.3"
    -- go.mod has pinned v1.74.4 since v1.56.0. The comment now says what the
    run-time patch is actually for.
    6e86ac4a
Loading
Loading