22#include "access/htup_details.h"
23#if PG_VERSION_NUM >= 120000
24#include "access/table.h"
26#include "access/heapam.h"
27#define table_open(r, l) heap_open((r), (l))
28#define table_close(r, l) heap_close((r), (l))
30#include "access/genam.h"
32#include "catalog/indexing.h"
33#include "catalog/namespace.h"
34#include "catalog/pg_attribute.h"
35#include "catalog/pg_constraint.h"
36#include "catalog/pg_index.h"
37#include "catalog/pg_type.h"
38#include "catalog/pg_enum.h"
39#include "catalog/pg_namespace.h"
40#include "catalog/pg_operator.h"
41#include "catalog/pg_type.h"
43#include "nodes/value.h"
44#include "parser/parse_func.h"
45#include "utils/fmgroids.h"
46#include "utils/syscache.h"
47#include "utils/lsyscache.h"
48#include "utils/inval.h"
92 bool was_unknown =
false;
95 if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
100 else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
106 result = OpernameGetOprid(opname, arg1, arg2);
107 if (OidIsValid(result))
113 Oid basetype = getBaseType(arg1);
115 if (basetype != arg1)
117 result = OpernameGetOprid(opname, basetype, basetype);
118 if (OidIsValid(result))
131 List *
const equals=list_make1(makeString(
"="));
133 FuncCandidateList clist;
134 Oid inputOids[2] = {ltypeId,rtypeId};
139 if(result!=InvalidOid)
142 clist = OpernameGetCandidates(equals,
'b',
false);
144 ncandidates = func_match_argtypes(2, inputOids,
147 if (ncandidates == 0)
149 else if (ncandidates == 1)
152 clist = func_select_candidate(2, inputOids, clist);
171 FuncCandidateList fcl=FuncnameGetCandidates(
172 list_make1(makeString(s)),
177#
if PG_VERSION_NUM >= 140000
197 FuncCandidateList fcl=FuncnameGetCandidates(
198 list_make2(makeString(
"provsql"),makeString(s)),
203#
if PG_VERSION_NUM >= 140000
228 const char *operatorName,
229 Oid operatorNamespace,
232 Oid *operatorObjectId,
233 Oid *functionObjectId)
238 tup = SearchSysCache4(OPERNAMENSP,
239 PointerGetDatum(operatorName),
240 ObjectIdGetDatum(leftObjectId),
241 ObjectIdGetDatum(rightObjectId),
242 ObjectIdGetDatum(operatorNamespace));
243 if (HeapTupleIsValid(tup))
245 Form_pg_operator oprform = (Form_pg_operator) GETSTRUCT(tup);
246#if PG_VERSION_NUM >= 120000
247 *operatorObjectId = oprform->oid;
249 *operatorObjectId = HeapTupleGetOid(tup);
251 *functionObjectId = oprform->oprcode;
252 defined = RegProcedureIsValid(oprform->oprcode);
253 ReleaseSysCache(tup);
261 *operatorObjectId = 0;
262 *functionObjectId = 0;
279 tup = SearchSysCache2(ENUMTYPOIDNAME,
280 ObjectIdGetDatum(enumtypoid),
281 CStringGetDatum(label));
282 if (!HeapTupleIsValid(tup))
285#if PG_VERSION_NUM >= 120000
286 ret = ((Form_pg_enum) GETSTRUCT(tup))->oid;
288 ret = HeapTupleGetOid(tup);
291 ReleaseSysCache(tup);
313 constants.
ok =
false;
316 #define CheckOid(o) if(constants.o==InvalidOid) { \
317 if(failure_if_not_possible) \
318 provsql_error("Could not initialize provsql constants"); \
330#
if PG_VERSION_NUM >= 120000
333 CStringGetDatum(
"provenance_gate"),
340#
if PG_VERSION_NUM >= 120000
343 CStringGetDatum(
"agg_token"),
369#if PG_VERSION_NUM >= 140000
386 CheckOid(OID_FUNCTION_PROVENANCE_PLUS);
389 CheckOid(OID_FUNCTION_PROVENANCE_TIMES);
392 CheckOid(OID_FUNCTION_PROVENANCE_MONUS);
395 CheckOid(OID_FUNCTION_PROVENANCE_PROJECT);
398 CheckOid(OID_FUNCTION_PROVENANCE_EQ);
404 CheckOid(OID_FUNCTION_PROVENANCE_DELTA);
407 CheckOid(OID_FUNCTION_PROVENANCE_AGGREGATE);
410 CheckOid(OID_FUNCTION_PROVENANCE_SEMIMOD);
419 CheckOid(OID_FUNCTION_PROVENANCE_CMP);
422 CheckOid(OID_FUNCTION_AGG_TOKEN_UUID);
434#
if PG_VERSION_NUM >= 120000
437 CStringGetDatum(
"random_variable"),
472 CheckOid(OID_OPERATOR_NOT_EQUAL_UUID);
473 CheckOid(OID_FUNCTION_NOT_EQUAL_UUID);
476 #define GET_GATE_TYPE_OID(x) { \
477 constants.GATE_TYPE_TO_OID[gate_ ## x] = get_enum_oid( \
478 constants.OID_TYPE_GATE_TYPE, \
480 if(constants.GATE_TYPE_TO_OID[gate_ ## x]==InvalidOid) \
481 provsql_error("Could not initialize provsql gate type " #x); }
497 #define GET_GATE_TYPE_OID_OPTIONAL(x) { \
498 constants.GATE_TYPE_TO_OID[gate_ ## x] = get_enum_oid( \
499 constants.OID_TYPE_GATE_TYPE, \
537 unsigned mid=(start+end)/2;
547 for(
unsigned i=0; i<start; ++i)
550 constants_cache2[start].
database=MyDatabaseId;
593 while(end >= start) {
594 int mid = (start + end) / 2;
602 if(insert_at) *insert_at = start;
613 for(
int i = 0; i < pos; ++i)
615 new_buf[pos].
relid = relid;
616 new_buf[pos].
valid =
true;
617 new_buf[pos].
present = present;
621 memcpy(new_buf[pos].block_key, info->
block_key,
639 if(relid == InvalidOid) {
728 while(end >= start) {
729 int mid = (start + end) / 2;
737 if(insert_at) *insert_at = start;
742 uint16 ancestor_n,
const Oid *ancestors)
746 for(
int i = 0; i < pos; ++i)
748 new_buf[pos].
relid = relid;
749 new_buf[pos].
valid =
true;
750 new_buf[pos].
present = present;
753 memcpy(new_buf[pos].ancestors, ancestors,
754 ancestor_n *
sizeof(Oid));
767 if(relid == InvalidOid) {
812 memcpy(e->
ancestors, ancestors, n *
sizeof(Oid));
820 memcpy(ancestors_out, ancestors, n *
sizeof(Oid));
859 while(end >= start) {
860 int mid = (start + end) / 2;
868 if(insert_at) *insert_at = start;
877 for(
int i = 0; i < pos; ++i)
879 new_buf[pos].
relid = relid;
880 new_buf[pos].
valid =
true;
884 memcpy(new_buf[pos].keys, keys->
keys,
897 if(relid == InvalidOid) {
936 conrel =
table_open(ConstraintRelationId, AccessShareLock);
938 Anum_pg_constraint_conrelid,
939 BTEqualStrategyNumber, F_OIDEQ,
940 ObjectIdGetDatum(relid));
941 scan = systable_beginscan(conrel,
942#
if PG_VERSION_NUM >= 110000
943 ConstraintRelidTypidNameIndexId,
945 ConstraintRelidIndexId,
947 true, NULL, 1, &skey);
949 while(HeapTupleIsValid(htup = systable_getnext(scan))) {
950 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(htup);
956 bool ok_not_null =
true;
958 if(con->contype != CONSTRAINT_PRIMARY && con->contype != CONSTRAINT_UNIQUE)
963 indexrelid = con->conindid;
964 if(!OidIsValid(indexrelid))
966 idxtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
967 if(!HeapTupleIsValid(idxtup))
969 idx = (Form_pg_index) GETSTRUCT(idxtup);
972 ReleaseSysCache(idxtup);
977 key->
col_n = (uint16) idx->indnatts;
978 for(k = 0; k < idx->indnatts; ++k) {
979 AttrNumber attno = idx->indkey.values[k];
980 key->
cols[k] = attno;
982 if(con->contype == CONSTRAINT_UNIQUE) {
984 SearchSysCache2(ATTNUM,
985 ObjectIdGetDatum(relid),
986 Int16GetDatum(attno));
987 if(!HeapTupleIsValid(atttup)) {
991 Form_pg_attribute attform = (Form_pg_attribute) GETSTRUCT(atttup);
992 if(!attform->attnotnull)
994 ReleaseSysCache(atttup);
1000 ReleaseSysCache(idxtup);
1008 systable_endscan(scan);
1011 return out->
key_n > 0;
1067 unsigned mid=(start+end)/2;
#define PROVSQL_TABLE_INFO_MAX_BLOCK_KEY
Cap on the number of block-key columns recorded per relation.
#define PROVSQL_TABLE_INFO_MAX_ANCESTORS
Cap on the number of base ancestors recorded per relation.
bool provsql_fetch_table_info(Oid relid, ProvenanceTableInfo *out)
C-callable IPC fetch for per-table provenance metadata.
bool provsql_fetch_ancestry(Oid relid, uint16 *ancestor_n_out, Oid *ancestors_out)
C-callable IPC fetch for the ancestor half of a per-table metadata record.
static bool key_cache_callback_registered
static unsigned table_info_cache_len
static bool table_info_callback_registered
const char * gate_type_name[]
Names of gate types.
static Oid get_enum_oid(Oid enumtypoid, const char *label)
Return the OID of a specific enum label within an enum type.
static int key_cache_find(Oid relid, int *insert_at)
static void invalidate_ancestry_cache_callback(Datum arg, Oid relid)
static void OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, Oid *operatorObjectId, Oid *functionObjectId)
Retrieve operator and function OIDs for a named operator.
Datum reset_constants_cache(PG_FUNCTION_ARGS)
SQL function to invalidate the OID constants cache.
Oid find_equality_operator(Oid ltypeId, Oid rtypeId)
Find the equality operator OID for two given types.
static void ancestry_cache_insert(int pos, Oid relid, bool present, uint16 ancestor_n, const Oid *ancestors)
#define GET_GATE_TYPE_OID_OPTIONAL(x)
bool provsql_lookup_ancestry(Oid relid, uint16 *ancestor_n_out, Oid *ancestors_out)
Look up the base-ancestor set of a tracked relation.
static Oid get_provsql_func_oid(char *s)
Return the OID of a provsql-schema function named s.
static database_constants_t * constants_cache
Per-database OID constants cache (sorted by database OID).
static void invalidate_table_info_cache_callback(Datum arg, Oid relid)
Relcache callback: PostgreSQL fires this whenever a relation's relcache entry is invalidated (locally...
bool provsql_lookup_table_info(Oid relid, ProvenanceTableInfo *out)
Look up per-table provenance metadata with a backend-local cache.
#define table_close(r, l)
static bool ancestry_callback_registered
static void table_info_cache_insert(int pos, Oid relid, bool present, const ProvenanceTableInfo *info)
Insert a fresh entry at pos (which must be the value returned by the most recent table_info_cache_fin...
static table_info_cache_entry * table_info_cache
Sorted by relid.
constants_t get_constants(bool failure_if_not_possible)
Retrieve the cached OID constants for the current database.
static unsigned constants_cache_len
Number of valid entries in constants_cache.
static int table_info_cache_find(Oid relid, int *insert_at)
Find relid in the cache.
static int ancestry_cache_find(Oid relid, int *insert_at)
static void invalidate_key_cache_callback(Datum arg, Oid relid)
bool provsql_lookup_relation_keys(Oid relid, ProvenanceRelationKeys *out)
Look up the PRIMARY-KEY and NOT-NULL-UNIQUE keys of a relation with a backend-local cache.
static unsigned ancestry_cache_len
static bool fetch_relation_keys(Oid relid, ProvenanceRelationKeys *out)
Read the PRIMARY-KEY and NOT-NULL-UNIQUE keys of relid from the system catalogs.
static Oid get_func_oid(char *s)
Return the OID of a globally qualified function named s.
static unsigned key_cache_len
static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2)
Look up an exactly matching binary operator OID.
#define GET_GATE_TYPE_OID(x)
static void key_cache_insert(int pos, Oid relid, const ProvenanceRelationKeys *keys)
static key_cache_entry * key_cache
static constants_t initialize_constants(bool failure_if_not_possible)
Query the system catalogs to populate a fresh constants_t.
static ancestry_cache_entry * ancestry_cache
Core types, constants, and utilities shared across ProvSQL.
#define PROVSQL_KEY_CACHE_MAX_KEY_COLS
#define PROVSQL_KEY_CACHE_MAX_KEYS
Upper bounds for the relation-key cache.
One PRIMARY-KEY or NOT-NULL-UNIQUE key on a relation.
AttrNumber cols[PROVSQL_KEY_CACHE_MAX_KEY_COLS]
Per-relation set of PRIMARY-KEY and NOT-NULL-UNIQUE keys.
ProvenanceRelationKey keys[PROVSQL_KEY_CACHE_MAX_KEYS]
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.
uint8_t kind
One of provsql_table_kind.
uint16 ancestor_n
when present: count
Oid ancestors[PROVSQL_TABLE_INFO_MAX_ANCESTORS]
when present: ancestor OIDs
Oid relid
pg_class OID (sort key)
bool present
when valid: did the worker return any ancestors?
bool valid
false => refresh on next access
Structure to store the value of various constants.
Oid OID_FUNCTION_PROVENANCE_EQ
OID of the provenance_eq FUNCTION.
Oid OID_FUNCTION_PROVENANCE_AGGREGATE
OID of the provenance_aggregate FUNCTION.
Oid OID_FUNCTION_PROVENANCE_SEMIMOD
OID of the provenance_semimod FUNCTION.
Oid OID_FUNCTION_PROVENANCE
OID of the provenance FUNCTION.
Oid OID_FUNCTION_AGG_TOKEN_UUID
OID of the agg_token_uuid FUNCTION.
Oid OID_FUNCTION_RV_AGGREGATE_SEMIMOD
OID of rv_aggregate_semimod helper (uuid, rv -> rv) used to wrap each per-row argument of an RV-retur...
Oid OID_TYPE_VARCHAR
OID of the VARCHAR TYPE.
Oid OID_FUNCTION_GATE_ZERO
OID of the provenance_zero FUNCTION.
Oid OID_SCHEMA_PROVSQL
OID of the provsql SCHEMA.
Oid OID_TYPE_GATE_TYPE
OID of the provenance_gate TYPE.
Oid OID_FUNCTION_PROVENANCE_PROJECT
OID of the provenance_project FUNCTION.
Oid OID_TYPE_FLOAT
OID of the FLOAT TYPE.
Oid OID_TYPE_AGG_TOKEN
OID of the agg_token TYPE.
Oid OID_FUNCTION_ARRAY_AGG
OID of the array_agg FUNCTION.
Oid OID_TYPE_INT
OID of the INT TYPE.
Oid OID_FUNCTION_PROVENANCE_PLUS
OID of the provenance_plus FUNCTION.
Oid OID_OPERATOR_NOT_EQUAL_UUID
OID of the <> operator on UUIDs FUNCTION.
Oid OID_TYPE_UUID
OID of the uuid TYPE.
Oid OID_TYPE_TSTZMULTIRANGE
OID of the tstzmultirange TYPE (PG14+, InvalidOid otherwise).
bool ok
true if constants were loaded
Oid OID_TYPE_INT_ARRAY
OID of the INT[] TYPE.
Oid OID_FUNCTION_PROVENANCE_DELTA
OID of the provenance_delta FUNCTION.
Oid OID_FUNCTION_ASSUME_BOOLEAN
OID of provsql.assume_boolean(uuid)->uuid.
Oid OID_FUNCTION_PROVENANCE_TIMES
OID of the provenance_times FUNCTION.
Oid OID_FUNCTION_PROVENANCE_MONUS
OID of the provenance_monus FUNCTION.
Oid OID_TYPE_BOOL
OID of the BOOL TYPE.
Oid OID_FUNCTION_NOT_EQUAL_UUID
OID of the = operator on UUIDs FUNCTION.
Oid OID_FUNCTION_GATE_ONE
OID of the provenance_one FUNCTION.
Oid OID_TYPE_NUMMULTIRANGE
OID of the nummultirange TYPE (PG14+, InvalidOid otherwise).
Oid OID_TYPE_UUID_ARRAY
OID of the uuid[] TYPE.
Oid OID_TYPE_RANDOM_VARIABLE
OID of the random_variable TYPE.
Oid OID_FUNCTION_PROVENANCE_CMP
OID of the provenance_cmp FUNCTION.
Oid OID_TYPE_INT4MULTIRANGE
OID of the int4multirange TYPE (PG14+, InvalidOid otherwise).
Oid OID_FUNCTION_RV_CMP[6]
OIDs of the random_variable_{eq,ne,le,lt,ge,gt} comparison procedure functions, indexed by the Compar...
Structure to store the value of various constants for a specific database.
Oid database
OID of the database these constants belong to.
constants_t constants
Cached OID constants for this database.
ProvenanceRelationKey keys[PROVSQL_KEY_CACHE_MAX_KEYS]
uint8 kind
when present: provsql_table_kind value
Oid relid
pg_class OID (sort key)
uint16 block_key_n
when present: number of block-key columns
AttrNumber block_key[PROVSQL_TABLE_INFO_MAX_BLOCK_KEY]
when present: block-key column numbers
bool present
when valid: was a record found at the worker?
bool valid
false => refresh on next access