---
id: 134c150de56c188c925476664026a1ff
author: Lemon Mint
title: 'gosuda.org/sqlite3: CGO_ENABLED=0 database/sql Driver Shared-Memory IPC:n välityksellä'
description: Go-kielinen, database/sql-yhteensopiva SQLite 3.54.1 -ajuri, joka toimii ilman CGO-riippuvuutta (CGO_ENABLED=0), tarjoaa HQQ-pohjaisen jaetun muistin työprosessien eristyksen, 64 KiB:n eräkohtaisen rivien esihakemisen sekä SLSA-todennetut binäärit.
language: fi
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` on Go-ohjelmointikielen `database/sql` -ajuri, joka on `CGO_ENABLED=0`-yhteensopiva ja ajaa alkuperäisen C-kielisen SQLite `3.54.1` -amalgaman eristetyssä työprosessissa [HQQ](https://gosuda.org/hqq):n jaetun muistin renkaiden kautta. Ajuri rekisteröityy vakionimellä `"sqlite3"`, tukee `github.com/mattn/go-sqlite3` -DSN-kyselyparametreja, sisältää upotetut SLSA-todennetut esikäännetyt palvelinbinäärit kuudelle käyttöjärjestelmän ja arkkitehtuurin kohteelle sekä käyttää kyselyiden putkitusta ja 64 KiB:n erien esihakua, minkä ansiosta se suoriutuu monirivisistä kyselyistä paremmin kuin prosessinsisäinen `cgo`.

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

## Miksi Toinen Go-SQLite-ajuri?

SQLite on yksi maailman laajimmin käytetyistä ohjelmistoista, mutta sen käyttäminen Go-kielestä on historiallisesti pakottanut kehittäjät epämukavaan valintaan rakennuksen yksinkertaisuuden ja moottorin uskollisuuden välillä.

Toisaalta on `github.com/mattn/go-sqlite3`, pitkäaikainen yhteisön vakiovalinta. Se kääri viralliset C-kielisen SQLite-amalgaman suoraan `cgo`:n kautta. Saat todellisen C-kielisen kyselyoptimoijan, täydet WAL-samanaikaisuussemantiikat ja ennustettavan C-muistinhallinnan. Hinta on `CGO_ENABLED=1`: paikalliset käännökset ja CI-putkistot hidastuvat, minimaaliset scratch- tai distroless-kontti-imagot vaativat vastaavat C-ajonaikaiset kirjastot, ristiinkääntäminen toiselle käyttöjärjestelmälle tai suoritinarkkitehtuurille vaatii täyden C-ristiinkääntötyökaluketjun, ja mikä tahansa C-koodin muistivaurio jakaa Go-prosessin osoiteavaruuden.

Toisaalta ovat puhtaan Go-kielen SQLite-portit, jotka on tuotettu mekaanisesti kääntämällä C-amalgama Go-lähdekoodiksi emuloidun C-ajonaikaisen ympäristön (`libc`) päälle. Ne palauttavat `CGO_ENABLED=0`:n, mikä tekee käännöksistä triviaaleja. Pitkäkestoisissa kuormissa käännetty C-keko ja rivikohtaiset Go-allokaatiot kuitenkin lisäävät roskienkeräyksen painetta, ja hienovaraiset reunatapaukset lukituksessa, varausaikakatkaisuissa tai lauseiden keskeytyksessä voivat poiketa natiiveista C-käännöksistä.

Rakensimme `gosuda.org/sqlite3`:n, jotta Go-sovelluksien ei tarvitse valita `CGO_ENABLED=0`:n ja todellisen C-kielisen SQLite-moottorin välillä. Kääntämällä virallisen SQLite `3.54.1` C-amalgaman omistettuun jaetun muistin palvelimeen (`hqq-sqlite-server`) ja kommunikoimalla `gosuda.org/hqq`:n kautta, Go-binääri käännetään `CGO_ENABLED=0`-tilassa ja suorittaa muokkaamatonta, `-O3`-optimoitua C-kielistä SQLite-koodia prosessirajan yli.

## Konfiguroinniton Suoritus: `go get`:stä `sql.Open`:iin

Olemassa olevan Go-koodikannan `github.com/mattn/go-sqlite3` -kirjaston korvaaminen vaatii ainoastaan tyhjän tuontipolun muuttamisen. Ajuri rekisteröityy nimellä `"sqlite3"` (ja `"hqq-sqlite"` eksplisiittistä valintaa varten) ja hyväksyy samat DSN-kyselymerkkijonot:

```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)
}
```

### Upotetut SLSA-todennetut työbinäärit

Luonnollinen kysymys, kun kuulee kirjaston käyttävän C-työprosessia, on: _"Pitääkö minun asentaa tai toimittaa erillinen C-binääri Go-ohjelmani rinnalle?"_

Ei. `gosuda.org/sqlite3` upottaa esikäännetyt `hqq-sqlite-server`-binäärit kaikille kuudelle pääkohteelle suoraan alustakohtaisiin Go-tiedostoihin (`internal/embedded/embed_<goos>_<goarch>.go`). Koska Go:n käännösrajoitteet kääntävät vain kohdetta `GOOS`:ia ja `GOARCH`:ia vastaavan tiedoston, `GOOS=linux GOARCH=arm64 go build` -ristiinkäännös upottaa automaattisesti vain noin 1,4 MiB:n kokoisen `linux/arm64`-palvelinbinäärin.

| Kohde-käyttöjärjestelmä | Kohdearkkitehtuuri (`GOARCH`) | Upotettu binääri                      | Käännöstyökalut ja alkuperä                       |
| :---------------------- | :---------------------------- | :------------------------------------ | :------------------------------------------------ |
| **Linux**               | `amd64`, `arm64`              | `hqq-sqlite-server_linux_<arch>`      | GCC `-O3`, SLSA Build L3 -alkuperä                |
| **macOS**               | `arm64`, `amd64`              | `hqq-sqlite-server_darwin_<arch>`     | AppleClang `-O3`, SLSA Build L3 -alkuperä         |
| **Windows**             | `amd64`                       | `hqq-sqlite-server_windows_amd64.exe` | MSVC `-O2`, SLSA Build L3 -alkuperä               |
| **Windows**             | `arm64`                       | `hqq-sqlite-server_windows_arm64.exe` | `zig cc -target aarch64-windows-gnu -O3`, SLSA L3 |

Kun `sql.Open` muodostaa ensimmäisen yhteyden, `autolaunch.go` purkaa upotetun binäärin käyttäjän välimuistihakemistoon (`$XDG_CACHE_HOME/hqq/bin/<sha256>/`), varmistaa sen kryptografisen SHA-256-tiivisteen vasten `hashes.go`-tiedoston kiinnitettyä `ReleaseHashes`-karttaa `gosuda.org/hqq/secureexec`-paketin avulla ja käynnistää työprosessin `--parent-stdin`-lipulla, jotta sen elinikä on tiukasti sidottu Go-prosessiisi.

### `mattn/go-sqlite3` DSN -yhteensopivuus puhtaasta lähteestä

Jotta ajuri toimisi todellisena suorana korvaajana, DSN-jäsennin (`dsn.go`) toteuttaa puhtaasta lähteestä rakennetun kopion yhteys- ja pragma-asetuksista, joita käytetään `mattn/go-sqlite3`-koodikannoissa:

| DSN-kyselyparametri                                                                           | Hyväksytyt arvot                                        | SQLite-vaikutus                                                                                      |
| :-------------------------------------------------------------------------------------------- | :------------------------------------------------------ | :--------------------------------------------------------------------------------------------------- |
| `_busy_timeout` / `_timeout`                                                                  | Kokonaisluku millisekunteina (esim. `5000`)             | Kutsuu `sqlite3_busy_timeout(db, ms)` istunnon avautuessa.                                           |
| `_journal_mode` / `_journal`                                                                  | `DELETE`, `TRUNCATE`, `PERSIST`, `MEMORY`, `WAL`, `OFF` | Suorittaa `PRAGMA journal_mode = <mode>`.                                                            |
| `_txlock`                                                                                     | `immediate`, `exclusive`, `deferred`                    | Valitsee `db.BeginTx`:lle joko `BEGIN IMMEDIATE`, `BEGIN EXCLUSIVE` tai `BEGIN DEFERRED`.            |
| `_foreign_keys` / `_fk`                                                                       | `on`, `true`, `1`, `off`, `false`, `0`                  | Suorittaa `PRAGMA foreign_keys = ON/OFF`.                                                            |
| `_synchronous` / `_sync`                                                                      | `0`/`OFF`, `1`/`NORMAL`, `2`/`FULL`, `3`/`EXTRA`        | Suorittaa `PRAGMA synchronous = <level>`.                                                            |
| `_cache_size`                                                                                 | Kokonaisluku sivuina tai `-KiB` (esim. `-20000`)        | Suorittaa `PRAGMA cache_size = <val>`.                                                               |
| `_loc`                                                                                        | `auto` tai IANA-aikavyöhyke (esim. `UTC`, `Asia/Seoul`) | Jäsentää `DATETIME`/`TIMESTAMP` tekstisarakkeet arvoiksi `*time.Time` kohdesijainnissa.              |
| `mode`                                                                                        | `ro`, `rw`, `rwc`, `memory`                             | Asettaa `SQLITE_OPEN_READONLY`, `SQLITE_OPEN_READWRITE`, `SQLITE_OPEN_CREATE` tai `SQLITE_OPEN_MEMORY`. |
| `_case_sensitive_like`, `_query_only`, `_recursive_triggers`, `_secure_delete`, `_AutoVacuum` | Totuusarvo tai tilakokonaisluku                         | Soveltaa vastaavan istunnon `PRAGMA`-asetuksen yhteyden alustuksessa.                                |

## Prosessieristyksen Muuttaminen Läpäisykyvyn Eduksi

Ensi silmäyksellä SQLiten ajaminen erillisessä prosessissa vaikuttaa väistämättä hitaammalta kuin `sqlite3_step`-kutsujen tekeminen prosessinsisäisesti `cgo`:n kautta. Käytännössä päinvastoin tapahtuu heti, kun kysely palauttaa enemmän kuin yhden rivin.

### Rivikohtaisten `cgo`-kutsujen piilokustannus

Tavanomaisessa `cgo`-SQLite-ajurissa `database/sql` ohjaa iterointia yksi rivi ja yksi sarake kerrallaan. 1 000 rivin lukeminen 4 sarakkeella aiheuttaa:

- 1 000 `cgo`-kutsua `sqlite3_step`:lle
- 4 000 `cgo`-kutsua `sqlite3_column_type`:lle sekä `sqlite3_column_int64`:lle / `sqlite3_column_text`:lle
- Tuhansia yksittäisiä rajanylityksiä Go-ajastimen ja C-pinon välillä

### Kyselyiden putkitus ja 64 KiB:n erien esihaku

`gosuda.org/sqlite3` poistaa rivikohtaiset rajanylitykset uudistamalla siirtoprotokollan kahden mekanismin ympärille, jotka sijaitsevat tiedostoissa `stmt.go`, `rows.go` ja `sqlite3/server/sqlite3_hooks.c`:

```text
Go-asiakas (stmt.go / rows.go)                      C11-työprosessi (sqlite3_hooks.c)
------------------------------                      ---------------------------------
1. Putkita yhdessä lennossa:
   ResetAsync + BindValuesAsync
   + StmtInfoAsync + FetchRowsAsync(128)  =======>  reset -> bind -> stmt_info ->
                                                    silmukka sqlite3_step() enintään 128 riville
                                          <=======  Erä 1 (rivit 1..128 pakattuna 64 KiB:n slotiin)
2. Laukaise välittömästi esihaku:
   FetchRowsAsync(128) (Erä 2)            =======>  silmukka sqlite3_step() riveille 129..256
   Kun C askeltaa Erää 2, Go-kutsuja
   lukee rivit 1..128 Erästä 1!           <=======  Erä 2 valmis jaetussa muistissa
```

1. **Yksittäislennon kyselyputkitus (`stmt.go`)**: Kun `QueryContext` tai `Stmt.QueryContext` suorittaa vain luku -lauseen, `s.query()` lähettää `reset`-, `bind_values`-, `stmt_info`- (ensimmäisellä suorituskerralla) ja `fetch_rows`-operaatiot asynkronisesti yhdessä jaetun muistin lennossa. Kaikki neljä operaatiota suoritetaan peräkkäin C-työprosessissa ja palautetaan yhdellä kierroksella.
2. **Tiiviit C-erisilmukat ja asynkroninen esihaku (`rows.go`)**: `fetch_rows`-funktion sisällä (`sqlite3_hooks.c`) C-työprosessi askeltaa `sqlite3_step(stmt)`:ia natiivissa C-silmukassa ja koodaa enintään `FetchSize`-riviä (oletus 128) suoraan 64 KiB:n jaetun muistin vastausslottiin, kunnes erän raja, slotti täyttyy tai `SQLITE_DONE` tapahtuu. Heti kun `rows.ingest()` on purkanut Erän 1, se laukaisee `FetchRowsAsync`:n Erälle 2 ennen ensimmäisen rivin palauttamista kutsujalle. Kun Go-koodisi lukee Erää 1, C-työprosessi askeltaa jo Erää 2 toisella suoritinytimellä.

Apple M4:llä (`darwin/arm64`) vertailu `gosuda.org/sqlite3`:n (`CGO_ENABLED=0`) ja `github.com/mattn/go-sqlite3`:n (`CGO_ENABLED=1`) välillä samalla SQLite-tietokannalla osoittaa erien käsittelyn ja putkituksen vaikutuksen:

| Kuorma                              | `gosuda.org/sqlite3` (`CGO_ENABLED=0`) | `mattn/go-sqlite3` (`CGO_ENABLED=1`) | Suhteellinen nopeus                  |
| :---------------------------------- | -------------------------------------: | -----------------------------------: | :----------------------------------- |
| **Pistehaku (`QueryRow` PK:lla)**   |            `3.52 µs/op` (9 B, 1 allokaatio) |     `3.56 µs/op` (232 B, 11 allokaatiota) | **1.01x (tasavertainen, 11x vähemmän allokaatioita)** |
| **100 rivin skannaus (`rows.Next`)** |    `20.41 µs/op` (30.5 KB, 211 allokaatiota) |  `36.34 µs/op` (21.8 KB, 309 allokaatiota) | **1.78x nopeampi**                   |
| **1 000 rivin skannaus (`rows.Next`)** |  `125.92 µs/op` (296 KB, 2 030 allokaatiota) | `349.10 µs/op` (216 KB, 3 009 allokaatiota) | **2.77x nopeampi**                   |
| **Valmisteltu lisäys (autocommit)**  |           `5.33 µs/op` (0 B, 0 allokaatiota) |      `5.88 µs/op` (120 B, 5 allokaatiota) | **1.10x nopeampi (0 allokaatiota)**  |
| **100 rivin transaktioerä**         |         `189.99 µs/op` (16 B, 1 allokaatio) | `191.50 µs/op` (12.1 KB, 503 allokaatiota) | **1.01x (500x vähemmän allokaatioita)** |

## Peruutus, polkuhiekkalaatikointi ja yhteysaltaan palautuminen

SQLiten ajaminen eristetyssä työprosessissa vahvistaa myös tapaa, jolla ajuri käsittelee aikakatkaisuja, luotettavia SQL-lauseita ja tiedostojärjestelmän rajoja:

- **Deterministinen kontekstin peruutus (`conn.go` ja `errors.go`)**: Jokainen ajurikutsu asettaa kevyen `context.AfterFunc`-vartijan (`cn.guard`). Jos kutsujan `context.Context` peruutetaan tai sen määräaika umpeutuu, kun hidas rekursiivinen kysely tai lukitusodotus on käynnissä palvelimella, vartija merkitsee yhteyden virheelliseksi, katkaisee paikallisen istuntoyhteyden ja lähettää kaistan ulkopuolisen `Cancel()`-kehyksen. C-työprosessi kutsuu välittömästi `sqlite3_interrupt(db)`:tä, mikä vapauttaa `sqlite3_step`:n, kun taas Go-ajuri kuvaa tuloksena olevan `SQLITE_INTERRUPT`-tilan arvoksi `context.Canceled` tai `context.DeadlineExceeded` ja ohjaa `database/sql`:n korvaamaan yhteyden altaassa.
- **Hakemistohiekkalaatikointi (`sqlsrv_pathrules.c`)**: C-työprosessi valvoo `--allow-dir`-polkusääntöjä jokaisella `open_v2`-kutsulla, selvittää symbolisia linkkejä ja hylkää sallitun hakemiston ulkopuolelle johtavat relatiiviset `..`-siirtymät. `sqlite3_load_extension` ja `SQLITE_LIMIT_ATTACHED` ovat oletuksena poissa käytöstä, jotta SQL-injektio ei voi poistua tietokantahakemistosta tai ladata mielivaltaisia jaettuja objekteja.

## Repositorion rakenne

Repositorio on jäsennelty siten, että ylätason paketti tarjoaa suoran `database/sql`-ajurin, kun taas `launcher/` ja `sqlite3/` ovat saatavilla edistyneitä mukautettuja palvelinkäyttöönottoja varten:

```text
gosuda.org/sqlite3
├── driver.go / api.go         # database/sql -ajurin rekisteröinti ("sqlite3") ja Connector-API
├── dsn.go                     # Puhtaasta lähteestä rakennettu mattn/go-sqlite3 DSN-jäsennin ja pragma-asetukset
├── conn.go / tx.go            # Istunnon elinkaari, kontekstivartija ja transaktiotilakone
├── stmt.go / rows.go          # Yksittäislennon pyyntöputkitus ja 64 KiB:n erien esihaku
├── errors.go                  # Tyypitetyt SQLiten ensisijaiset/laajennetut virhekoodit ja vartijavastaavuus
├── autolaunch.go / hashes.go  # Konfiguroinniton upotetun palvelimen purkaminen ja SHA-256-kiinnitys
├── internal/embedded/         # Alustakohtaiset //go:embed-binäärit (linux, darwin, windows)
├── launcher/                  # Konfiguroitava prosessivalvoja mukautettuja palvelinkäyttöönottoja varten
└── sqlite3/                   # Generoitu hqq-bindgen Go-asiakas ja C11 SQLite-palvelinlähdekoodi
    └── server/                # C11-palvelintoteutus (sqlite3_hooks.c, sqlsrv_policy.c)
```

## Aloittaminen

Asenna moduuli `go get`-komennolla ja avaa tietokantasi komennolla `sql.Open("sqlite3", dsn)`:

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

- **GitHub-repositorio**: [https://github.com/gosuda/hqq-sqlite3](https://github.com/gosuda/hqq-sqlite3)
- **DSN- ja pragma-viite**: [docs/DSN.md](https://github.com/gosuda/hqq-sqlite3/blob/main/docs/DSN.md)
- **Arkkitehtuuri ja siirtoprotokolla**: [docs/ARCHITECTURE.md](https://github.com/gosuda/hqq-sqlite3/blob/main/docs/ARCHITECTURE.md)
