/** * @file MMappedTableInfo.h * @brief Per-relation provenance metadata: the in-memory record. * * A @c ProvenanceTableInfo describes one relation ProvSQL tracks, and * feeds the safe-query optimisation: the planner-time hierarchy detector * needs to know whether each base relation is TID (independent leaves; * the default after @c add_provenance) or BID (block-correlated leaves; * produced by @c repair_key) before it can decide whether a query is safe * to rewrite into read-once form. * * The records live in the @c provsql.table_info heap table * (@c table_info.c), where metadata about relations belongs: every change * follows the transaction that made it, and @c pg_dump carries them. * This struct is what the C side reads them into. * * Before ProvSQL 1.13.0 they lived in a fifth mmap-backed file, * @c provsql_table_info.mmap, laid out as a fixed-stride vector of this * struct behind the usual 16-byte ProvSQL header. * @c provsql.migrate_table_info() (@c TableInfoMigrate.cpp) still reads * that layout, which is why the field order below must not change while * any installation may still have such a file to import. */ #ifndef MMAPPED_TABLE_INFO_H #define MMAPPED_TABLE_INFO_H #ifdef __cplusplus #include #else #include #endif #ifdef __cplusplus extern "C" { #endif #include "postgres.h" #include "access/attnum.h" #ifdef __cplusplus } #endif /** * @brief Cap on the number of block-key columns recorded per relation. * * BID tables (produced by @c repair_key) can have multi-column keys. * We store the column numbers inline in a fixed-size array so each * record is fixed-stride and @c MMappedVector can back the file * directly. Sixteen is generous in practice – provenance-tracked * tables rarely use composite keys wider than a handful of columns. * @c repair_key raises a clear error if a wider key is requested. */ #define PROVSQL_TABLE_INFO_MAX_BLOCK_KEY 16 /** * @brief Cap on the number of base ancestors recorded per relation. * * The base-ancestor set lists the @c pg_class OIDs of the original * @c add_provenance / @c repair_key relations a derived (CTAS / @c * SELECT @c INTO / @c CREATE @c MATERIALIZED @c VIEW) relation's * provenance ultimately reads from. Base tables carry @c {self}; the * safe-query rewriter consults the set to enforce that joined FROM * entries have disjoint base ancestors before firing the read-once * factoring. Sixty-four covers practical CTAS workloads (typical * derivations span 1-10 sources); set-ancestors raises a clear error * if a wider set is requested, in which case the relation should be * left untracked (the safe-query rewriter will then refuse it on the * missing-ancestry conservative path). */ #define PROVSQL_TABLE_INFO_MAX_ANCESTORS 64 /** * @brief How the provenance leaves of a tracked relation are correlated. * * Three cases need distinguishing for the safe-query rewriter: * * - @c PROVSQL_TABLE_TID -- independent input leaves; the * post-@c add_provenance default. Each row's provenance token is a * fresh @c gate_input with its own probability. * - @c PROVSQL_TABLE_BID -- block-correlated leaves produced by * @c repair_key. Rows sharing the same value of @c block_key are * mutually exclusive (they originate from a single block * @c gate_input via @c gate_mulinput children). An empty * @c block_key means the whole table is one block. * - @c PROVSQL_TABLE_OPAQUE -- correlations are unknown. Used for * relations whose provenance is derived from a tracked source via * @c CREATE @c TABLE @c AS @c SELECT, @c INSERT @c INTO @c SELECT, * or @c UPDATE under @c provsql.update_provenance. The safe-query * rewriter must bail on these. * * Stored as @c uint8_t in @c ProvenanceTableInfo so the on-disk size * matches the previous @c bool field exactly. * * @warning ON-DISK ABI: these integer values are persisted in * @c provsql_table_info.mmap. Do not reorder or renumber existing * members; new kinds must be appended. */ typedef enum provsql_table_kind { PROVSQL_TABLE_TID = 0, PROVSQL_TABLE_BID = 1, PROVSQL_TABLE_OPAQUE = 2 } provsql_table_kind; /** * @brief Per-relation metadata for the safe-query optimisation. * * One record per provenance-tracked relation. @c relid is the * @c pg_class OID of the relation and acts as the primary key during * linear lookup. @c kind discriminates between TID, BID, and OPAQUE * (see @c provsql_table_kind). For BID, @c block_key[0..block_key_n-1] * lists the column numbers whose tuples partition the table into * mutually-exclusive blocks; an empty key means the whole table is * one block. @c block_key is left empty for TID and OPAQUE. * @c ancestors[0..ancestor_n-1] lists the @c pg_class OIDs of the * original @c add_provenance / @c repair_key base relations this * relation's atoms ultimately come from (a sorted, deduplicated set). * Base tables have @c ancestor_n @c == @c 1 with @c ancestors[0] * @c == @c relid; CTAS-derived tables inherit the union of their * sources' ancestor sets. @c ancestor_n @c == @c 0 means the * registry has no information for this relation -- the safe-query * rewriter then conservatively refuses to fire when ancestry-based * disjointness is required. */ typedef struct ProvenanceTableInfo { Oid relid; ///< pg_class OID of the relation (primary key) uint8_t kind; ///< One of @c provsql_table_kind uint16_t block_key_n; ///< Number of valid entries in @c block_key AttrNumber block_key[PROVSQL_TABLE_INFO_MAX_BLOCK_KEY]; ///< Block-key column numbers uint16_t ancestor_n; ///< Number of valid entries in @c ancestors (0 = no registry info) Oid ancestors[PROVSQL_TABLE_INFO_MAX_ANCESTORS]; ///< Sorted, deduplicated base-relation OIDs } ProvenanceTableInfo; #endif /* MMAPPED_TABLE_INFO_H */