ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
TableInfoMigrate.cpp
Go to the documentation of this file.
1/**
2 * @file TableInfoMigrate.cpp
3 * @brief One-shot import of the legacy per-relation metadata file.
4 *
5 * Before ProvSQL 1.13.0, the per-relation TID / BID / OPAQUE metadata
6 * lived in a fifth mmap file, @c provsql_table_info.mmap, alongside the
7 * circuit store; it now lives in the @c provsql.table_info heap table
8 * (see @c table_info.c). @c provsql.migrate_table_info() reads the old
9 * file, when the database still has one, and inserts every record it
10 * holds that the table does not already carry.
11 *
12 * The file is read directly by the calling backend, read-only: nothing
13 * writes it any more, so there is no worker round-trip and no locking
14 * to arrange. Records for relations that no longer exist are skipped
15 * (the old file had no way to drop an entry for a relation dropped
16 * while the extension was absent).
17 */
18#include <string>
19
20#include <unistd.h>
21
22extern "C" {
23#include "postgres.h"
24#include "catalog/pg_type.h"
25#include "common/relpath.h"
26#include "executor/spi.h"
27#include "fmgr.h"
28#include "miscadmin.h"
29#include "utils/array.h"
30#include "utils/builtins.h"
31#include "utils/syscache.h"
32#include "provsql_utils.h"
33}
34
35#include "MMappedTableInfo.h"
36#include "MMappedVector.hpp"
37
38/** @brief Magic of the legacy @c provsql_table_info.mmap header
39 * ("PvSTblIn"), as written by ProvSQL 1.6.0 to 1.12.0. */
40static constexpr uint64_t LEGACY_TABLE_INFO_MAGIC =
41 uint64_t('P') | uint64_t('v') << 8 | uint64_t('S') << 16 | uint64_t('T') << 24 |
42 uint64_t('b') << 32 | uint64_t('l') << 40 | uint64_t('I') << 48 | uint64_t('n') << 56;
43
44/** @brief Textual label of a persisted @c provsql_table_kind value. */
45static const char *kindLabel(uint8_t kind)
46{
47 switch(kind) {
48 case PROVSQL_TABLE_TID: return "tid";
49 case PROVSQL_TABLE_BID: return "bid";
50 default: return "opaque";
51 }
52}
53
54extern "C" {
55
56PG_FUNCTION_INFO_V1(migrate_table_info);
57
58/**
59 * @brief Import the legacy metadata file into @c provsql.table_info.
60 * @return The number of rows inserted; 0 when there is no file to read
61 * or every record it holds is already present.
62 */
63Datum migrate_table_info(PG_FUNCTION_ARGS)
64{
65 char *rel = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace);
66 std::string path = std::string(DataDir) + "/" + rel
67 + "/provsql_table_info.mmap";
68 pfree(rel);
69
70 if(access(path.c_str(), R_OK) != 0)
71 PG_RETURN_INT64(0);
72
73 int64 inserted = 0;
74
75 if(SPI_connect() != SPI_OK_CONNECT)
76 provsql_error("Cannot connect to SPI while migrating provsql.table_info");
77
78 try {
79 MMappedVector<ProvenanceTableInfo> legacy(path.c_str(), true,
81
82 for(unsigned long i = 0; i < legacy.nbElements(); ++i) {
83 const ProvenanceTableInfo &info = legacy[i];
84 Oid argtypes[4] = { OIDOID, TEXTOID, INT2ARRAYOID, OIDARRAYOID };
85 Datum values[4];
86 Datum *elems;
87 int rc;
88
89 /* Tombstoned entries, and entries whose relation is long gone. */
90 if(info.relid == InvalidOid)
91 continue;
92 if(!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(info.relid)))
93 continue;
94
95 values[0] = ObjectIdGetDatum(info.relid);
96 values[1] = CStringGetTextDatum(kindLabel(info.kind));
97
98 elems = (Datum *) palloc(sizeof(Datum) *
99 (info.block_key_n ? info.block_key_n : 1));
100 for(uint16_t k = 0; k < info.block_key_n; ++k)
101 elems[k] = Int16GetDatum(info.block_key[k]);
102 values[2] = PointerGetDatum(
103 construct_array(elems, info.block_key_n, INT2OID, 2, true, 's'));
104 pfree(elems);
105
106 elems = (Datum *) palloc(sizeof(Datum) *
107 (info.ancestor_n ? info.ancestor_n : 1));
108 for(uint16_t k = 0; k < info.ancestor_n; ++k)
109 elems[k] = ObjectIdGetDatum(info.ancestors[k]);
110 values[3] = PointerGetDatum(
111 construct_array(elems, info.ancestor_n, OIDOID, sizeof(Oid), true, 'i'));
112 pfree(elems);
113
114 rc = SPI_execute_with_args(
115 "INSERT INTO provsql.table_info(relid, kind, block_key, ancestors) "
116 "VALUES ($1::regclass, $2, $3, $4) ON CONFLICT (relid) DO NOTHING",
117 4, argtypes, values, NULL, false, 0);
118 if(rc != SPI_OK_INSERT)
119 provsql_error("Cannot insert into provsql.table_info (SPI code %d)", rc);
120 inserted += SPI_processed;
121 }
122 } catch(const std::exception &e) {
123 SPI_finish();
124 provsql_error("migrate_table_info: cannot read %s: %s",
125 path.c_str(), e.what());
126 }
127
128 SPI_finish();
129 PG_RETURN_INT64(inserted);
130}
131
132}
Per-relation provenance metadata: the in-memory record.
@ PROVSQL_TABLE_TID
@ PROVSQL_TABLE_BID
Template implementation of MMappedVector<T>.
Datum migrate_table_info(PG_FUNCTION_ARGS)
Import the legacy metadata file into provsql.table_info.
static const char * kindLabel(uint8_t kind)
Textual label of a persisted provsql_table_kind value.
static constexpr uint64_t LEGACY_TABLE_INFO_MAGIC
Magic of the legacy provsql_table_info.mmap header ("PvSTblIn"), as written by ProvSQL 1....
Append-only, mmap-backed vector of elements of type T.
unsigned long nbElements() const
Return the number of elements currently stored.
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
Core types, constants, and utilities shared across ProvSQL.
Per-relation metadata for the safe-query optimisation.
Oid relid
pg_class OID of the relation (primary key)
AttrNumber block_key[PROVSQL_TABLE_INFO_MAX_BLOCK_KEY]
Block-key column numbers.
uint16_t block_key_n
Number of valid entries in block_key.
Oid ancestors[PROVSQL_TABLE_INFO_MAX_ANCESTORS]
Sorted, deduplicated base-relation OIDs.
uint8_t kind
One of provsql_table_kind.
uint16_t ancestor_n
Number of valid entries in ancestors (0 = no registry info).