package granary

  1. Overview
  2. Docs
Pure-OCaml SQL engine

Install

dune-project
 Dependency

Authors

Maintainers

Sources

0.0.3.tar.gz
sha256=8b18780ea373be48301d9f333925860a2f9110fc0ac28684295118d72b65a67e
sha512=25ca3c9c5e2b528704a542502e0f37dc33ba003f65622d969b8c2b800778585f8ef0cf89b36e6679832e3993e8303aecddfc662742baf7044d6afe4a796b8f11

doc/granary.sql/Granary_sql/Exec/index.html

Module Granary_sql.ExecSource

Execute write operations against the store and catalog.

Transaction mode for DML operations. Auto wraps each DML operation in its own RW transaction (autocommit). In_txn tx reuses an externally managed transaction; the caller is responsible for committing or rolling back. In_ro_txn tx (#274) reads every scan through one externally managed RO snapshot so a multi-statement read sees a single point-in-time committed state; read-only — using it on a write path raises.

Sourceval execute : ?mode:txn_mode -> ?clock:(unit -> float) option -> ?params:Granary_encoding.Row.value array -> ?before_hook: (tx:Granary_store.Store.rw Granary_store.Store.txn -> new_row:Granary_encoding.Row.t option -> old_row:Granary_encoding.Row.t option -> unit Lwt.t) option -> ?after_hook: (tx:Granary_store.Store.rw Granary_store.Store.txn -> new_row:Granary_encoding.Row.t option -> old_row:Granary_encoding.Row.t option -> unit Lwt.t) option -> ?on_replace_delete_before: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> unit Lwt.t) option -> ?on_replace_delete: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> unit Lwt.t) option -> ?on_upsert_update_before: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> new_row:Granary_encoding.Row.t -> unit Lwt.t) option -> ?on_upsert_update: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> new_row:Granary_encoding.Row.t -> unit Lwt.t) option -> Granary_store.Store.t -> Granary_catalog.Catalog.t -> Plan.op -> unit Lwt.t

Execute a write operation (Plan.op) against the store and catalog. Runs in its own autocommit RW transaction unless ?mode supplies an enclosing one; the optional hooks observe row changes for triggers and REPLACE/UPSERT bookkeeping.

Sourceval execute_with_count : ?mode:txn_mode -> ?clock:(unit -> float) option -> ?params:Granary_encoding.Row.value array -> ?before_hook: (tx:Granary_store.Store.rw Granary_store.Store.txn -> new_row:Granary_encoding.Row.t option -> old_row:Granary_encoding.Row.t option -> unit Lwt.t) option -> ?after_hook: (tx:Granary_store.Store.rw Granary_store.Store.txn -> new_row:Granary_encoding.Row.t option -> old_row:Granary_encoding.Row.t option -> unit Lwt.t) option -> ?on_replace_delete_before: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> unit Lwt.t) option -> ?on_replace_delete: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> unit Lwt.t) option -> ?on_upsert_update_before: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> new_row:Granary_encoding.Row.t -> unit Lwt.t) option -> ?on_upsert_update: (tx:Granary_store.Store.rw Granary_store.Store.txn -> old_row:Granary_encoding.Row.t -> new_row:Granary_encoding.Row.t -> unit Lwt.t) option -> Granary_store.Store.t -> Granary_catalog.Catalog.t -> Plan.op -> int Lwt.t

Like execute, but returns the rows-affected count. For DDL ops (CREATE TABLE, CREATE INDEX) this is 0; for INSERT it is 1; for UPDATE it is the number of rows whose contents were modified. Op_begin, Op_commit, and Op_rollback are not handled here — they raise Failure if passed; the Db layer intercepts them.

Sourcetype query_stats = {
  1. mutable rows_examined : int;
  2. mutable rows_returned : int;
  3. mutable used_index : bool;
}

#239: per-query cost/stats signal for an external cost-based cache. rows_examined is the number of rows pulled from a base table/index scan — the true work signal (a query that scans a million rows to return one reads rows_examined = 1_000_000, rows_returned = 1); rows_returned is the result size once the stream is drained; used_index is the plan-time fact that the base access is an index/rowid/FTS seek rather than a full scan.

Mutable counters updated as the stream is consumed: pass a fresh record to query via ?stats, drain the stream, then read the fields. Mirage-pure (no clock/Unix dependency). rows_examined covers seq scans, index/rowid lookups (incl. nested-loop-join right-side probes), the count fast path, both inputs of a hash join, FTS scans (content rows in a plain scan, matched index rows in a MATCH query), and rows read inside scalar/correlated subqueries (#257).

Sourceval make_query_stats : unit -> query_stats

A zeroed query_stats (used_index = false).

Sourcetype row_change =
  1. | Inserted of {
    1. rowid : int64;
    2. row : Granary_encoding.Row.t;
    }
  2. | Deleted of {
    1. rowid : int64;
    2. row : Granary_encoding.Row.t;
    }
  3. | Updated of {
    1. rowid : int64;
    2. old_row : Granary_encoding.Row.t;
    3. new_row : Granary_encoding.Row.t;
    }

#417 Phase 0: one row-level mutation captured by a change-capturing dirty_tables_acc. rowid is the row's int64 rowid; rows are the full Granary_encoding.Row.t as written/removed. Updated carries both the pre-image (old_row) and post-image (new_row).

Sourcetype dirty_tables_acc

#240: opaque accumulator for the set of user tables a write statement mutated. Install it around a statement with with_dirty and read the result with dirty_elements. A capturing accumulator (make_change_acc) additionally records the per-row row_change deltas, read with dirty_changes (#417).

Sourceval make_dirty_acc : unit -> dirty_tables_acc

A fresh, empty dirty_tables_acc that records mutated table names only.

Sourceval make_change_acc : unit -> dirty_tables_acc

#417: a fresh accumulator that additionally captures the per-row row_change deltas (read with dirty_changes). Row capture is opt-in: make_dirty_acc callers pay nothing for it.

Sourceval with_dirty : dirty_tables_acc -> (unit -> 'a Lwt.t) -> 'a Lwt.t

with_dirty acc f runs f with acc installed as the active write-path mutation sink, so every table whose rows f mutates — directly, or indirectly via FK cascades and triggers — is recorded in acc. Nestable and independent of the query stats context. Schema-changing DDL (ALTER/DROP) is intentionally not recorded, even when it rewrites rows (e.g. ALTER TABLE … DROP COLUMN): DDL invalidation is handled out of band (see Granary_db.Db.dirty_tables).

Sourceval current_dirty_acc : unit -> dirty_tables_acc option

The accumulator installed by the nearest enclosing with_dirty, if any. Lets a caller (the #427 reactive-view driver) reuse an ambient change-capturing accumulator instead of shadowing it with a fresh one.

Sourceval dirty_elements : dirty_tables_acc -> string list

The user tables recorded in acc: sorted, deduplicated, with SQLite-reserved sqlite_… objects (sqlite_master / sqlite_sequence) excluded.

Sourceval dirty_changes : dirty_tables_acc -> (string * row_change list) list

#417: the per-row row_change deltas recorded in acc, as (table, changes) pairs sorted by table name, each table's changes in application order. SQLite-reserved sqlite_… objects are excluded, matching dirty_elements. Always [] for a non-capturing accumulator (make_dirty_acc).

Sourceval quote_ident : string -> string

#264: quote a SQL identifier with double-quotes when it is not a plain [A-Za-z_][A-Za-z0-9_]* word (embedded quotes doubled); returned verbatim otherwise.

Sourceval ddl_of_table : Granary_catalog.Catalog.table_meta -> string

#264: reconstruct a CREATE TABLE statement from catalog metadata (used by both sqlite_master and the logical dump). Emits column types, constraints (NOT NULL, column-level PRIMARY KEY, DEFAULT, CHECK, GENERATED), foreign keys, and the WITHOUT ROWID clause. UNIQUE and composite/table-level PRIMARY KEY constraints are carried by their backing indexes (ddl_of_index), not inline.

Sourceval ddl_of_index : Granary_catalog.Catalog.index_info -> string

#264: reconstruct a CREATE [UNIQUE] INDEX statement from index metadata.

#264: reconstruct a CREATE VIRTUAL TABLE .. USING fts5(..) statement.

Sourceval read_fts_content_rows : Granary_store.Store.t -> txn_mode -> Granary_catalog.Catalog.fts_table_meta -> (int64 * string list) list Lwt.t

#330: read an FTS5 table's stored content as (rowid, column_texts) pairs through mode (the dump's shared snapshot / explicit txn), so Db.dump can emit INSERT INTO fts(rowid, ..) statements that round-trip rowids exactly. Rowids are surfaced only here (out-of-band), not via any SQL projection.

Sourceval sql_literal_of_value : Granary_encoding.Row.value -> string

#264: render a Granary_encoding.Row.value as a standalone SQL literal that re-reads to the identical value (text quoted, blob as X'..', float as the shortest round-tripping REAL literal, non-finite floats as 1e999/-1e999/NULL). Used to serialize rows as INSERT statements.

Sourceval query : ?mode:txn_mode -> ?clock:(unit -> float) option -> ?params:Granary_encoding.Row.value array -> ?stats:query_stats -> Granary_store.Store.t -> Granary_catalog.Catalog.t -> Plan.op -> Granary_encoding.Row.t Lwt_stream.t Lwt.t

Execute read operations; returns a lazy stream of result rows. params are the positional parameter values for ? placeholders. clock supplies the current Unix timestamp for SQL date/time functions invoked with the literal 'now'. mode selects the read's transaction context: Auto reads a fresh RO snapshot of the committed state, whereas In_txn tx reads through tx so the result reflects the transaction's own uncommitted writes (read-your-own-writes, #262) — across scans, index/rowid lookups, the aggregate fast path, indexed joins, FTS scans, and subqueries. stats, when supplied, is populated as the returned stream is consumed (#239); omit it and the read path is entirely unaffected.

Sourceval eval_expr : (unit -> float) option -> Granary_encoding.Row.value array -> Granary_encoding.Row.t -> Plan.expr -> Granary_encoding.Row.value

Evaluate a Plan.expr against a row. Exposed primarily for testing the rich expression language directly without round-tripping through SQL. Failures (e.g. division by zero, type-mismatched arithmetic) raise Failure.