# 3.2 Persistent Tables

_Peios / Advanced Peios / loregd / Storage_

> The four data tables every hive database has — keys, path entries, values and blanket tombstones — and their columns.

Each hive is one SQLite database, and every hive database has the same
four data tables. loregd creates them on first boot (§2.2, step 4).

The tables hold what the kernel gives loregd and nothing derived from it.
Security descriptors are stored as opaque blobs, GUIDs and sequence
numbers are assigned by the kernel, and no table records a resolved or
filtered view of anything.

## 3.2.1 keys

```sql
CREATE TABLE keys (
    guid           BLOB NOT NULL PRIMARY KEY,
    name           TEXT NOT NULL,
    name_folded    TEXT NOT NULL,
    parent_guid    BLOB,
    sd             BLOB NOT NULL,
    volatile       INTEGER NOT NULL DEFAULT 0,
    symlink        INTEGER NOT NULL DEFAULT 0,
    last_write_time INTEGER NOT NULL
);
```

| Column | Meaning |
|---|---|
| `guid` | The 16-byte key GUID assigned by the kernel. Primary key. |
| `name` | The key's own name component, with case preserved as written. |
| `name_folded` | The folded form of `name` (§3.4), used for case-insensitive lookup. |
| `parent_guid` | The parent key's GUID; null for the hive root, which is how the root is identified. |
| `sd` | The security descriptor, in binary self-relative form. Opaque to loregd. |
| `volatile` | 1 for a volatile key, 0 for a persistent one. In this table it is always 0 — volatile keys live in the volatile database (§3.3). |
| `symlink` | 1 if the key is a symbolic link. |
| `last_write_time` | Unix nanoseconds. |

## 3.2.2 path_entries

```sql
CREATE TABLE path_entries (
    parent_guid       BLOB NOT NULL,
    child_name        TEXT NOT NULL,
    child_name_folded TEXT NOT NULL,
    layer             TEXT NOT NULL,
    target_type       INTEGER NOT NULL,
    target_guid       BLOB,
    sequence          INTEGER NOT NULL,
    PRIMARY KEY (parent_guid, child_name_folded, layer)
);

CREATE INDEX idx_path_entries_target
    ON path_entries (target_guid)
    WHERE target_type = 0;
```

A path entry is one layer's opinion about one child name under one
parent. Several layers may hold entries for the same name; resolving
between them is the kernel's job, not loregd's.

| Column | Meaning |
|---|---|
| `parent_guid` | The parent key's GUID. |
| `child_name` | The child name with case preserved. |
| `child_name_folded` | The folded form, which is what the primary key uses — so a name collides case-insensitively within a layer. |
| `layer` | The layer name. Compared as binary, so layer names *are* case-sensitive, unlike key names. |
| `target_type` | 0 for a GUID entry (the key exists in this layer), 1 for HIDDEN (a tombstone masking lower layers). |
| `target_guid` | The target key's GUID when `target_type` is 0; null for HIDDEN. |
| `sequence` | The kernel-assigned sequence number. |

The partial index on `target_guid` covers only non-HIDDEN rows. It is
what makes the reverse lookup — which path entries point at this key —
cheap, and that reverse lookup is what orphan detection (§2.2, step 6)
and `RSI_DROP_KEY` need.

## 3.2.3 values

```sql
CREATE TABLE [values] (
    key_guid       BLOB NOT NULL,
    name           TEXT NOT NULL,
    name_folded    TEXT NOT NULL,
    layer          TEXT NOT NULL,
    type           INTEGER NOT NULL,
    data           BLOB,
    sequence       INTEGER NOT NULL,
    PRIMARY KEY (key_guid, name_folded, layer)
);
```

| Column | Meaning |
|---|---|
| `key_guid` | The key this value belongs to. |
| `name` | The value name, case preserved. The empty string is the key's default value. |
| `name_folded` | The folded form; also the empty string for the default value. |
| `layer` | The layer this value entry belongs to. |
| `type` | The registry value type — `REG_SZ` is 1, `REG_DWORD` is 4, and so on. `REG_TOMBSTONE` (`0xFFFF`) marks a per-value tombstone. |
| `data` | The value payload; null for a tombstone. |
| `sequence` | The kernel-assigned sequence number. |

`values` is a reserved word in SQL, so every reference to this table is
quoted — `[values]`, or `main.[values]` and `volatile.[values]` when the
schema is named explicitly. Unquoted, it is a syntax error.

## 3.2.4 blanket_tombstones

```sql
CREATE TABLE blanket_tombstones (
    key_guid       BLOB NOT NULL,
    layer          TEXT NOT NULL,
    sequence       INTEGER NOT NULL,
    PRIMARY KEY (key_guid, layer)
);
```

A blanket tombstone hides *every* value a key holds in the layers beneath
it, rather than naming one value the way a `REG_TOMBSTONE` entry does.
One row per key per layer.
