File
Blob: kv/sqlite3/sqlutil.go
| 1 | package sqlite3 |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "database/sql" |
| 6 | "strings" |
| 7 | ) |
| 8 | |
| 9 | // withWriteTx executes fn within a write transaction. |
| 10 | func withWriteTx(ctx context.Context, db *sql.DB, fn func(tx *sql.Tx) error) error { |
| 11 | tx, err := db.BeginTx(ctx, nil) |
| 12 | if err != nil { |
| 13 | return err |
| 14 | } |
| 15 | if err := fn(tx); err != nil { |
| 16 | _ = tx.Rollback() |
| 17 | return err |
| 18 | } |
| 19 | return tx.Commit() |
| 20 | } |
| 21 | |
| 22 | // withReadTx executes fn within a read-only transaction. |
| 23 | func withReadTx(ctx context.Context, db *sql.DB, fn func(tx *sql.Tx) error) error { |
| 24 | tx, err := db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) |
| 25 | if err != nil { |
| 26 | return err |
| 27 | } |
| 28 | if err := fn(tx); err != nil { |
| 29 | _ = tx.Rollback() |
| 30 | return err |
| 31 | } |
| 32 | return tx.Commit() |
| 33 | } |
| 34 | |
| 35 | // placeholders returns a comma-separated string of n "?" placeholders. |
| 36 | func placeholders(n int) string { |
| 37 | if n <= 0 { |
| 38 | return "" |
| 39 | } |
| 40 | return strings.Repeat("?,", n-1) + "?" |
| 41 | } |
| 42 | |
| 43 | // bindUint64AsInt64 converts a uint64 to int64 for SQLite INTEGER binding. |
| 44 | // SQLite stores all integers as signed 64-bit. Values derived from |
| 45 | // chord.Hash (48-bit) and lease tokens (positive UnixNano) fit safely. |
| 46 | func bindUint64AsInt64(v uint64) int64 { |
| 47 | return int64(v) |
| 48 | } |
| 49 | |
| 50 | // scanInt64AsUint64 converts a scanned int64 back to uint64. |
| 51 | func scanInt64AsUint64(v int64) uint64 { |
| 52 | return uint64(v) |
| 53 | } |