---
id: 134c150de56c188c925476664026a1ff
author: Lemon Mint
title: 'gosuda.org/sqlite3: CGO_ENABLED=0 database/sql Driver nad IPC so zdieľanou pamäťou'
description: Drop-in ovládač database/sql pre SQLite 3.54.1 pre Go s CGO_ENABLED=0, izoláciou pracovných procesov pomocou zdieľanej pamäte HQQ, predbežným načítavaním dávok riadkov po 64 KiB a binárnymi súbormi s overeniami SLSA.
language: sk
date: 2026-10-18T14:02:16.803040007Z
path: /sqlite3
go_package: gosuda.org/sqlite3
go_repourl: https://github.com/gosuda/hqq-sqlite3.git
category: database
---

`gosuda.org/sqlite3` je ovládač `database/sql` pre Go s `CGO_ENABLED=0`, ktorý spúšťa upstream C SQLite `3.54.1` amalgamáciu v izolovanom pracovnom procese cez zdieľané pamäťové kruhové buffery [HQQ](https://gosuda.org/hqq). Registruje sa pod štandardným názvom ovládača `"sqlite3"`, podporuje parametre DSN dotazu z `github.com/mattn/go-sqlite3`, obsahuje vopred zostavené serverové binárky s SLSA atestáciou pre šesť cieľových operačných systémov a architektúr a využíva pipelining požiadaviek a predbežné načítavanie dávok po 64 KiB, vďaka čomu prekonáva in-process `cgo` pri dotazoch vracajúcich viacero riadkov.

```bash
go get gosuda.org/sqlite3@v0.3.3540100
```

## Prečo ďalší ovládač SQLite pre Go?

SQLite patrí medzi najrozšírenejšie softvérové komponenty na svete, no jeho používanie v Go historicky nútilo vývojárov k nepríjemnej voľbe medzi jednoduchosťou zostavenia a vernosťou k engine.

Na jednej strane stojí `github.com/mattn/go-sqlite3`, dlhoročný komunitný štandard. Priamo obaľuje oficiálnu C amalgamáciu SQLite cez `cgo`. Získate skutočný C plánovač dotazov, plnú sémantiku súbežnosti WAL a predvídateľnú správu pamäte v C. Cenou je `CGO_ENABLED=1`: lokálne zostavenia a CI pipeline sa spomaľujú, minimálne scratch alebo distroless kontajnerové obrazy vyžadujú zodpovedajúce C runtime knižnice, krížová kompilácia pre iný operačný systém alebo architektúru procesora vyžaduje úplný C krížový toolchain a akákoľvek poškodená pamäť v C zdieľa adresný priestor procesu Go.

Na druhej strane sú čisto Go porty SQLite, generované mechanickým prekladom C amalgamácie do zdrojového kódu Go nad emulovaným C runtime (`libc`). Obnovujú `CGO_ENABLED=0`, čo robí zostavenie triviálnym. Pri dlhotrvajúcej záťaži však preložená C halda a alokácie Go pre jednotlivé riadky zvyšujú tlak na garbage collector a jemné hraničné prípady v zamykaní, časoch čakania (busy timeout) alebo prerušení príkazov sa môžu odchyľovať od natívnych C zostavení.

Vytvorili sme `gosuda.org/sqlite3`, aby aplikácie v Go nemuseli voliť medzi `CGO_ENABLED=0` a skutočným C enginom SQLite. Skompilovaním oficiálnej C amalgamácie SQLite `3.54.1` do špecializovaného serveru so zdieľanou pamäťou (`hqq-sqlite-server`) a komunikáciou cez `gosuda.org/hqq` sa vaša binárka v Go zostavuje s `CGO_ENABLED=0` a zároveň vykonáva nezmenenú, `-O3` optimalizovanú C SQLite naprieč hranicou procesu.

## Konfigurácia nulovej záťaže: Od `go get` po `sql.Open`

Nahradenie `github.com/mattn/go-sqlite3` v existujúcom kóde v Go vyžaduje zmenu iba cesty anonymného importu. Ovládač sa registruje ako `"sqlite3"` (a `"hqq-sqlite"` pre explicitný výber) a akceptuje rovnaké reťazce DSN:

```go
package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	_ "gosuda.org/sqlite3"
)

func main() {
	dsn := "file:app.db?_journal_mode=WAL&_busy_timeout=5000&_txlock=immediate&_foreign_keys=on"
	db, err := sql.Open("sqlite3", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	ctx := context.Background()
	if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)`); err != nil {
		log.Fatal(err)
	}
	if _, err := db.ExecContext(ctx, `INSERT INTO users (name) VALUES (?)`, "Ada Lovelace"); err != nil {
		log.Fatal(err)
	}

	var id int64
	var name string
	if err := db.QueryRowContext(ctx, `SELECT id, name FROM users WHERE name = ?`, "Ada Lovelace").Scan(&id, &name); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("user #%d: %s\n", id, name)
}
```

### Vložené serverové binárky s SLSA atestáciou

Prirodzenou otázkou, keď sa dozviete, že knižnica používa pracovný proces v C, je: _„Musím so svojím programom v Go inštalovať alebo distribuovať samostatnú C binárku?“_

Nie. `gosuda.org/sqlite3` vkladá vopred zostavené binárky `hqq-sqlite-server` pre všetkých šesť hlavných cieľov priamo do Go súborov označených podľa platformy (`internal/embedded/embed_<goos>_<goarch>.go`). Keďže obmedzenia zostavenia v Go kompilujú iba súbor zodpovedajúci vášmu cieľovému `GOOS` a `GOARCH`, krížová kompilácia príkazom `GOOS=linux GOARCH=arm64 go build` automaticky vloží iba binárku servera `linux/arm64` s veľkosťou približne 1,4 MiB.

| Cieľový OS  | Cieľová architektúra (`GOARCH`) | Vložená binárka                       | Zostavovací toolchain a pôvod                     |
| :---------- | :------------------------------ | :------------------------------------ | :------------------------------------------------ |
| **Linux**   | `amd64`, `arm64`                | `hqq-sqlite-server_linux_<arch>`      | GCC `-O3`, SLSA Build L3 Provenance               |
| **macOS**   | `arm64`, `amd64`                | `hqq-sqlite-server_darwin_<arch>`     | AppleClang `-O3`, SLSA Build L3 Provenance        |
| **Windows** | `amd64`                         | `hqq-sqlite-server_windows_amd64.exe` | MSVC `-O2`, SLSA Build L3 Provenance              |
| **Windows** | `arm64`                         | `hqq-sqlite-server_windows_arm64.exe` | `zig cc -target aarch64-windows-gnu -O3`, SLSA L3 |

Keď `sql.Open` nadviaže svoje prvé spojenie, `autolaunch.go` materializuje vloženú binárku do používateľského adresára vyrovnávacej pamäte (`$XDG_CACHE_HOME/hqq/bin/<sha256>/`), overí jej kryptografický digest SHA-256 voči pevne určenej mape `ReleaseHashes` v `hashes.go` pomocou `gosuda.org/hqq/secureexec` a spustí pracovný proces s parametrom `--parent-stdin`, aby jeho životnosť bola prísne viazaná na váš proces Go.

### Čistá reimplementácia DSN kompatibility s `mattn/go-sqlite3`

Aby fungoval ako skutočná náhrada bez úprav, analyzátor DSN (`dsn.go`) implementuje čistú reimplementáciu pripojení a nastavení pragma, ktoré sa používajú naprieč kódovými základňami `mattn/go-sqlite3`:

| Parameter DSN dotazu                                                                          | Akceptované hodnoty                                      | Efekt v SQLite                                                                                        |
| :-------------------------------------------------------------------------------------------- | :------------------------------------------------------- | :---------------------------------------------------------------------------------------------------- |
| `_busy_timeout` / `_timeout`                                                                  | Celé číslo v milisekundách (napr. `5000`)                | Volá `sqlite3_busy_timeout(db, ms)` pri otvorení relácie.                                             |
| `_journal_mode` / `_journal`                                                                  | `DELETE`, `TRUNCATE`, `PERSIST`, `MEMORY`, `WAL`, `OFF`  | Vykoná `PRAGMA journal_mode = <mode>`.                                                                |
| `_txlock`                                                                                     | `immediate`, `exclusive`, `deferred`                     | Vyberá `BEGIN IMMEDIATE`, `BEGIN EXCLUSIVE` alebo `BEGIN DEFERRED` pre `db.BeginTx`.                  |
| `_foreign_keys` / `_fk`                                                                       | `on`, `true`, `1`, `off`, `false`, `0`                   | Vykoná `PRAGMA foreign_keys = ON/OFF`.                                                                |
| `_synchronous` / `_sync`                                                                      | `0`/`OFF`, `1`/`NORMAL`, `2`/`FULL`, `3`/`EXTRA`         | Vykoná `PRAGMA synchronous = <level>`.                                                                |
| `_cache_size`                                                                                 | Celočíselný počet strán alebo `-KiB` (napr. `-20000`)    | Vykoná `PRAGMA cache_size = <val>`.                                                                   |
| `_loc`                                                                                        | `auto` alebo IANA časové pásmo (napr. `UTC`, `Asia/Seoul`) | Parsuje textové stĺpce `DATETIME`/`TIMESTAMP` do `*time.Time` v cieľovej lokalite.                  |
| `mode`                                                                                        | `ro`, `rw`, `rwc`, `memory`                              | Nastavuje `SQLITE_OPEN_READONLY`, `SQLITE_OPEN_READWRITE`, `SQLITE_OPEN_CREATE` alebo `SQLITE_OPEN_MEMORY`. |
| `_case_sensitive_like`, `_query_only`, `_recursive_triggers`, `_secure_delete`, `_AutoVacuum` | Booleovská hodnota alebo celočíselný režim               | Aplikuje zodpovedajúci reláciový `PRAGMA` pri inicializácii pripojenia.                              |

## Premena izolácie procesov na výhodu priepustnosti

Na prvý pohľad sa môže zdať, že spustenie SQLite v samostatnom procese musí byť pomalšie ako volanie `sqlite3_step` v rámci procesu cez `cgo`. V praxi sa však deje opak hneď, ako dotaz vráti viac než jeden riadok.

### Skrytá cena volaní `cgo` riadok po riadku

V bežnom ovládači SQLite cez `cgo` `database/sql` iteruje jeden riadok a jeden stĺpec naraz. Čítanie 1 000 riadkov so 4 stĺpcami spôsobí:

- 1 000 volaní `cgo` na `sqlite3_step`
- 4 000 volaní `cgo` na `sqlite3_column_type` a `sqlite3_column_int64` / `sqlite3_column_text`
- tisíce jednotlivých prechodov hranicou medzi plánovačom Go a zásobníkom C

### Pipelining požiadaviek a predbežné načítavanie dávok po 64 KiB

`gosuda.org/sqlite3` odstraňuje prechody hranicou pre jednotlivé riadky tým, že ppretvára protokol komunikácie okolo dvoch mechanizmov v `stmt.go`, `rows.go` a `sqlite3/server/sqlite3_hooks.c`:

```text
Go Client (stmt.go / rows.go)                       C11 Worker (sqlite3_hooks.c)
-----------------------------                       ----------------------------
1. Pipeline in 1 flight:
   ResetAsync + BindValuesAsync
   + StmtInfoAsync + FetchRowsAsync(128)  =======>  reset -> bind -> stmt_info ->
                                                    loop sqlite3_step() up to 128 rows
                                          <=======  Batch 1 (rows 1..128 packed in 64 KiB slot)
2. Immediately fire prefetch:
   FetchRowsAsync(128) (Batch 2)          =======>  loop sqlite3_step() for rows 129..256
   While C steps Batch 2, Go caller
   scans rows 1..128 from Batch 1!        <=======  Batch 2 ready in shared memory
```

1. **Pipelining dotazu v jednom lete (`stmt.go`)**: Keď `QueryContext` alebo `Stmt.QueryContext` spustí príkaz len na čítanie, `s.query()` odošle `reset`, `bind_values`, `stmt_info` (pri prvom vykonaní) a `fetch_rows` asynchrónne v jedinom lete cez zdieľanú pamäť. Všetky štyri operácie sa vykonajú za sebou na pracovnom procese v C a vrátia sa v jednom obehu.
2. **Tesné dávkové slučky v C a asynchrónne predbežné načítavanie (`rows.go`)**: Vnútri `fetch_rows` (`sqlite3_hooks.c`) pracovný proces v C volá `sqlite3_step(stmt)` v natívnej slučke C a kóduje až `FetchSize` riadkov (predvolene 128) priamo do odpovedného slotu zdieľanej pamäte o veľkosti 64 KiB, kým sa nedosiahne limit dávky, slot sa nezaplní alebo nenastane `SQLITE_DONE`. Hneď ako `rows.ingest()` dekóduje dávku 1, odošle `FetchRowsAsync` pre dávku 2 skôr, než vráti prvý riadok volajúcemu. Kým váš kód v Go prechádza dávku 1, pracovný proces v C už na inom jadre procesora spracúva dávku 2.

Na Apple M4 (`darwin/arm64`) ukazuje porovnanie `gosuda.org/sqlite3` (`CGO_ENABLED=0`) s `github.com/mattn/go-sqlite3` (`CGO_ENABLED=1`) nad tou istou databázou SQLite efekt dávkovania a pipeliningu:

| Záťaž                               | `gosuda.org/sqlite3` (`CGO_ENABLED=0`) |  `mattn/go-sqlite3` (`CGO_ENABLED=1`) | Relatívna rýchlosť                   |
| :---------------------------------- | -------------------------------------: | ------------------------------------: | :----------------------------------- |
| **Bodový výber (`QueryRow` podľa PK)** |            `3.52 µs/op` (9 B, 1 alloc) |       `3.56 µs/op` (232 B, 11 allocs) | **1.01x (parita, 11x menej alokácií)** |
| **Prechod 100 riadkami (`rows.Next`)**  |    `20.41 µs/op` (30.5 KB, 211 allocs) |   `36.34 µs/op` (21.8 KB, 309 allocs) | **1.78x rýchlejšie**                 |
| **Prechod 1 000 riadkami (`rows.Next`)** |  `125.92 µs/op` (296 KB, 2,030 allocs) | `349.10 µs/op` (216 KB, 3,009 allocs) | **2.77x rýchlejšie**                 |
| **Prepared Insert (Autocommit)**    |           `5.33 µs/op` (0 B, 0 allocs) |        `5.88 µs/op` (120 B, 5 allocs) | **1.10x rýchlejšie (0 alokácií)**    |
| **Dávka transakcie so 100 riadkami** |         `189.99 µs/op` (16 B, 1 alloc) |  `191.50 µs/op` (12.1 KB, 503 allocs) | **1.01x (500x menej alokácií)**      |

## Zrušenie, izolácia ciest a obnova poolu pripojení

Spustenie SQLite v izolovanom pracovnom procese tiež posilňuje spôsob, akým ovládač spracúva časové limity, nedôveryhodný SQL a hranice súborového systému:

- **Deterministické zrušenie kontextu (`conn.go` a `errors.go`)**: Každé volanie ovládača aktivuje ľahkú stráž `context.AfterFunc` (`cn.guard`). Ak je `context.Context` volajúceho zrušený alebo jeho termín vyprší, kým na serveri beží pomalý rekurzívny dotaz alebo čakanie na zámok, stráž označí pripojenie ako chybné, ukončí lokálne prepojenie relácie a odošle mimopásmový rámec `Cancel()`. Pracovný proces v C okamžite zavolá `sqlite3_interrupt(db)`, čím uvoľní `sqlite3_step`, zatiaľ čo ovládač v Go mapuje výsledný stav `SQLITE_INTERRUPT` na `context.Canceled` alebo `context.DeadlineExceeded` a pokyne `database/sql`, aby nahradil pripojenie v poole.
- **Izolácia adresárov (`sqlsrv_pathrules.c`)**: Pracovný proces v C vynucuje pravidlá ciest `--allow-dir` pri každom volaní `open_v2`, rieši symbolické odkazy a odmieta relatívne prechody `..` mimo povoleného adresára. `sqlite3_load_extension` a `SQLITE_LIMIT_ATTACHED` sú predvolene vypnuté, takže SQL injekcia nemôže uniknúť z adresára databázy ani načítať ľubovoľné zdieľané objekty.

## Štruktúra repozitára

Repozitár je usporiadaný tak, že hlavný balík poskytuje ovládač `database/sql` pripravený na okamžité použitie, zatiaľ čo `launcher/` a `sqlite3/` zostávajú dostupné pre pokročilé nasadenia vlastných serverov:

```text
gosuda.org/sqlite3
├── driver.go / api.go         # database/sql driver registration ("sqlite3") and Connector API
├── dsn.go                     # Clean-room mattn/go-sqlite3 DSN parser and pragma configuration
├── conn.go / tx.go            # Session lifecycle, context guard, and transaction state machine
├── stmt.go / rows.go          # Single-flight request pipelining and 64 KiB batch prefetching
├── errors.go                  # Typed SQLite primary/extended error codes and sentinel matching
├── autolaunch.go / hashes.go  # Zero-config embedded server materialization and SHA-256 pinning
├── internal/embedded/         # Platform-tagged //go:embed binaries (linux, darwin, windows)
├── launcher/                  # Configurable process supervisor for custom server deployments
└── sqlite3/                   # Generated hqq-bindgen Go client and C11 SQLite server source
    └── server/                # C11 server implementation (sqlite3_hooks.c, sqlsrv_policy.c)
```

## Začíname

Nainštalujte modul pomocou `go get` a otvorte svoju databázu pomocou `sql.Open("sqlite3", dsn)`:

```bash
go get gosuda.org/sqlite3@v0.3.3540100
```

- **GitHub repozitár**: [https://github.com/gosuda/hqq-sqlite3](https://github.com/gosuda/hqq-sqlite3)
- **Referencia DSN a pragma**: [docs/DSN.md](https://github.com/gosuda/hqq-sqlite3/blob/main/docs/DSN.md)
- **Architektúra a protokol komunikácie**: [docs/ARCHITECTURE.md](https://github.com/gosuda/hqq-sqlite3/blob/main/docs/ARCHITECTURE.md)
