ouroboros-consensus
Safe HaskellNone
LanguageHaskell2010

Ouroboros.Consensus.Storage.LeiosDB.Impl.SQLite.Primitives

Description

Low-level SQLite primitives that turn every SQLite error into a LeiosDbException.

Synopsis

Documentation

useStmt ∷ Statement → IO a → IO a Source #

Run an action on a pre-prepared statement and always sqlite3_reset it afterwards, regardless of outcome. Reset uses raw reset (no error re-throw) because SQLite reports the previous step's error via reset; we let the original exception propagate instead.

dbBindUtf8 ∷ HasCallStack ⇒ Statement → ParamIndex → ByteString → IO () Source #

Bind as TEXT. Needed for JSON1 payloads: json_each interprets BLOB arguments as JSONB (SQLite ≥ 3.45), our payload is ASCII JSON.

dbFinalize ∷ Statement → IO () Source #

Finalize a statement, exactly once, ignoring the return code.

sqlite3_finalize always frees the statement; its return code merely replays the most recent evaluation's error (sticky, like reset -- see useStmt). Neither retrying nor throwing is ever right here: a busy-retry would call sqlite3_finalize on freed memory (the use-after-free behind the devnet segfaults of 2026-08-31), and a throw would propagate from bracket cleanup.

withStmt ∷ HasCallStack ⇒ Database → String → (Statement → IO a) → IO a Source #

Prepare a statement, run the action, finalize.

orCloseOnError ∷ Database → IO a → IO a Source #

Close the connection if the action throws, then rethrow. For whatever is acquired on a fresh connection -- an attach, a schema, a statement -- after the open succeeded and before anything owns the close.

dbWithTransaction ∷ HasCallStack ⇒ Database → IO a → IO a Source #

A read-only transaction: BEGIN DEFERRED, so readers do not exclude each other. Any transaction that writes must use dbWithWriteTransaction.

dbWithWriteTransactionRaw ∷ HasCallStack ⇒ Database → IO a → IO a Source #

dbWithWriteTransaction for the maintenance paths (promotion to immutable, GC), which hold a raw Database rather than a Conn.

dbStepSafe ∷ HasCallStack ⇒ Statement → IO StepResult Source #

dbStep through the safe FFI call (step rather than stepNoCB): a safe call does not block its RTS capability, so the potentially long-running maintenance statements (copy, GC) must use it.

dbStep1Safe ∷ HasCallStack ⇒ Statement → IO () Source #

dbStep1 through the safe FFI call; see dbStepSafe.

readSingleInt64 ∷ HasCallStack ⇒ Statement → IO Int64 Source #

Read a single-row, single-column integer result, stepping (safe FFI) through to completion -- which also suits RETURNING statements, whose write only certainly happened once they report Done.

readReturningInt64 ∷ Statement → IO Int64 Source #

Read a single-column Int64 from a statement that uses a RETURNING clause on a PK-scoped UPDATE (i.e. produces exactly one row followed by Done). Any other shape is a programmer error.

queryInt64 ∷ HasCallStack ⇒ Database → String → IO Int64 Source #

Run a query that yields exactly one integer column.

collectBlobs ∷ HasCallStack ⇒ Statement → IO [ByteString] Source #

Step a statement (safe FFI) to completion, collecting blob column 0.

execJson ∷ HasCallStack ⇒ Statement → ByteString → IO () Source #

Bind a JSON payload (jsonHexArray) to parameter 1 and execute the statement via non-blocking Safe FFI.

dbStepInsert ∷ HasCallStack ⇒ Statement → IO Bool Source #

Like dbStep1 but returns True on success and False on constraint violation (duplicate key). Other errors are thrown as usual.

dbStepInsertOrTrace ∷ HasCallStack ⇒ Tracer IO TraceLeiosDb → String → String → Statement → IO () Source #

Step an INSERT statement, absorbing UNIQUE/PRIMARY KEY violations and emitting a TraceLeiosDbInsertCollision for each one. The caller supplies a table label and a key description for the trace.

After a constraint error, sqlite3_reset reports the same error code; the normal dbReset would re-throw it, so we use raw reset and discard the return value. This also leaves the statement in a clean state for the subsequent bracket-time dbFinalize to succeed.

jsonHexArray ∷ [ByteString] → ByteString Source #

Build a JSON array of hex-encoded blobs: ["aabb...","1234...",...]. Consumed on the SQL side via json_each(?) + unhex(je.value).

jsonIntArray ∷ [Int] → ByteString Source #

Build a JSON array of integers: [1,2,3,...]. Same consumer pattern as jsonHexArray (values are already ints, so no decoding step).

withDie ∷ HasCallStack ⇒ Database → IO (Either Error a) → IO a Source #

Run a database action that may return an error, and throw a LeiosDbException if it does.

Including ErrorBusy: the connections set a busy_timeout, so SQLite has already waited that long in C before reporting it. Waiting again on top of that only converts a lock nobody is going to release into an unbounded stall -- and with one writer per partition, a lock nobody is going to release means another process has the file.