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"
95 bool was_unknown =
false;
98 if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
103 else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
109 result = OpernameGetOprid(opname, arg1, arg2);
110 if (OidIsValid(result))
116 Oid basetype = getBaseType(arg1);
118 if (basetype != arg1)
120 result = OpernameGetOprid(opname, basetype, basetype);
121 if (OidIsValid(result))
134 List *
const equals=list_make1(makeString(
"="));
136 FuncCandidateList clist;
137 Oid inputOids[2] = {ltypeId,rtypeId};
142 if(result!=InvalidOid)
145 clist = OpernameGetCandidates(equals,
'b',
false);
147 ncandidates = func_match_argtypes(2, inputOids,
150 if (ncandidates == 0)
152 else if (ncandidates == 1)
155 clist = func_select_candidate(2, inputOids, clist);
174 FuncCandidateList fcl=FuncnameGetCandidates(
175 list_make1(makeString(s)),
180#
if PG_VERSION_NUM >= 140000
200 FuncCandidateList fcl=FuncnameGetCandidates(
201 list_make2(makeString(
"provsql"),makeString(s)),
206#
if PG_VERSION_NUM >= 140000
231 const char *operatorName,
232 Oid operatorNamespace,
235 Oid *operatorObjectId,
236 Oid *functionObjectId)
241 tup = SearchSysCache4(OPERNAMENSP,
242 PointerGetDatum(operatorName),
243 ObjectIdGetDatum(leftObjectId),
244 ObjectIdGetDatum(rightObjectId),
245 ObjectIdGetDatum(operatorNamespace));
246 if (HeapTupleIsValid(tup))
248 Form_pg_operator oprform = (Form_pg_operator) GETSTRUCT(tup);
249#if PG_VERSION_NUM >= 120000
250 *operatorObjectId = oprform->oid;
252 *operatorObjectId = HeapTupleGetOid(tup);
254 *functionObjectId = oprform->oprcode;
255 defined = RegProcedureIsValid(oprform->oprcode);
256 ReleaseSysCache(tup);
264 *operatorObjectId = 0;
265 *functionObjectId = 0;
282 tup = SearchSysCache2(ENUMTYPOIDNAME,
283 ObjectIdGetDatum(enumtypoid),
284 CStringGetDatum(label));
285 if (!HeapTupleIsValid(tup))
288#if PG_VERSION_NUM >= 120000
289 ret = ((Form_pg_enum) GETSTRUCT(tup))->oid;
291 ret = HeapTupleGetOid(tup);
294 ReleaseSysCache(tup);
316 constants.
ok =
false;
319 #define CheckOid(o) if(constants.o==InvalidOid) { \
320 if(failure_if_not_possible) \
321 provsql_error("Could not initialize provsql constants"); \
333#
if PG_VERSION_NUM >= 120000
336 CStringGetDatum(
"provenance_gate"),
343#
if PG_VERSION_NUM >= 120000
346 CStringGetDatum(
"agg_token"),
372#if PG_VERSION_NUM >= 140000
389 CheckOid(OID_FUNCTION_PROVENANCE_PLUS);
392 CheckOid(OID_FUNCTION_PROVENANCE_TIMES);
395 CheckOid(OID_FUNCTION_PROVENANCE_MONUS);
398 CheckOid(OID_FUNCTION_PROVENANCE_PROJECT);
401 CheckOid(OID_FUNCTION_PROVENANCE_EQ);
407 CheckOid(OID_FUNCTION_PROVENANCE_DELTA);
410 CheckOid(OID_FUNCTION_PROVENANCE_AGGREGATE);
413 CheckOid(OID_FUNCTION_PROVENANCE_SEMIMOD);
422 CheckOid(OID_FUNCTION_PROVENANCE_CMP);
425 CheckOid(OID_FUNCTION_AGG_TOKEN_UUID);
429 CheckOid(OID_FUNCTION_GET_CHILDREN);
438 Oid argtypes[1] = { ANYARRAYOID };
439 constants.
OID_UNNEST = LookupFuncName(list_make1(makeString(
"unnest")),
454#
if PG_VERSION_NUM >= 120000
457 CStringGetDatum(
"random_variable"),
537 CheckOid(OID_OPERATOR_NOT_EQUAL_UUID);
538 CheckOid(OID_FUNCTION_NOT_EQUAL_UUID);
541 #define GET_GATE_TYPE_OID(x) { \
542 constants.GATE_TYPE_TO_OID[gate_ ## x] = get_enum_oid( \
543 constants.OID_TYPE_GATE_TYPE, \
545 if(constants.GATE_TYPE_TO_OID[gate_ ## x]==InvalidOid) \
546 provsql_error("Could not initialize provsql gate type " #x); }
562 #define GET_GATE_TYPE_OID_OPTIONAL(x) { \
563 constants.GATE_TYPE_TO_OID[gate_ ## x] = get_enum_oid( \
564 constants.OID_TYPE_GATE_TYPE, \
613 unsigned mid=(start+end)/2;
637 for(
unsigned i=0; i<start; ++i)
640 constants_cache2[start].
database=MyDatabaseId;
641 constants_cache2[start].
constants=constants;
683 while(end >= start) {
684 int mid = (start + end) / 2;
692 if(insert_at) *insert_at = start;
703 for(
int i = 0; i < pos; ++i)
705 new_buf[pos].
relid = relid;
706 new_buf[pos].
valid =
true;
707 new_buf[pos].
present = present;
711 memcpy(new_buf[pos].block_key, info->
block_key,
729 if(relid == InvalidOid) {
818 while(end >= start) {
819 int mid = (start + end) / 2;
827 if(insert_at) *insert_at = start;
832 uint16 ancestor_n,
const Oid *ancestors)
836 for(
int i = 0; i < pos; ++i)
838 new_buf[pos].
relid = relid;
839 new_buf[pos].
valid =
true;
840 new_buf[pos].
present = present;
843 memcpy(new_buf[pos].ancestors, ancestors,
844 ancestor_n *
sizeof(Oid));
857 if(relid == InvalidOid) {
902 memcpy(e->
ancestors, ancestors, n *
sizeof(Oid));
910 memcpy(ancestors_out, ancestors, n *
sizeof(Oid));
949 while(end >= start) {
950 int mid = (start + end) / 2;
958 if(insert_at) *insert_at = start;
967 for(
int i = 0; i < pos; ++i)
969 new_buf[pos].
relid = relid;
970 new_buf[pos].
valid =
true;
974 memcpy(new_buf[pos].keys, keys->
keys,
987 if(relid == InvalidOid) {
1026 conrel =
table_open(ConstraintRelationId, AccessShareLock);
1028 Anum_pg_constraint_conrelid,
1029 BTEqualStrategyNumber, F_OIDEQ,
1030 ObjectIdGetDatum(relid));
1031 scan = systable_beginscan(conrel,
1032#
if PG_VERSION_NUM >= 110000
1033 ConstraintRelidTypidNameIndexId,
1035 ConstraintRelidIndexId,
1037 true, NULL, 1, &skey);
1039 while(HeapTupleIsValid(htup = systable_getnext(scan))) {
1040 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(htup);
1046 bool ok_not_null =
true;
1048 if(con->contype != CONSTRAINT_PRIMARY && con->contype != CONSTRAINT_UNIQUE)
1053 indexrelid = con->conindid;
1054 if(!OidIsValid(indexrelid))
1056 idxtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1057 if(!HeapTupleIsValid(idxtup))
1059 idx = (Form_pg_index) GETSTRUCT(idxtup);
1062 ReleaseSysCache(idxtup);
1067 key->
col_n = (uint16) idx->indnatts;
1068 for(k = 0; k < idx->indnatts; ++k) {
1069 AttrNumber attno = idx->indkey.values[k];
1070 key->
cols[k] = attno;
1072 if(con->contype == CONSTRAINT_UNIQUE) {
1074 SearchSysCache2(ATTNUM,
1075 ObjectIdGetDatum(relid),
1076 Int16GetDatum(attno));
1077 if(!HeapTupleIsValid(atttup)) {
1078 ok_not_null =
false;
1081 Form_pg_attribute attform = (Form_pg_attribute) GETSTRUCT(atttup);
1082 if(!attform->attnotnull)
1083 ok_not_null =
false;
1084 ReleaseSysCache(atttup);
1090 ReleaseSysCache(idxtup);
1098 systable_endscan(scan);
1101 return out->
key_n > 0;
1157 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
@ gate_assumed
Structural marker over a single child whose sub-circuit was computed under a Boolean-provenance assum...
#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_REGULAR_INDICATOR
OID of provsql.regular_indicator(boolean): the deterministic gate_one/gate_zero indicator the planner...
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_CHOOSE
OID of the choose(anyelement) aggregate (keeps the first non-NULL value); used to decorrelate scalar ...
Oid OID_FUNCTION_ANNOTATE
OID of provsql.annotate(uuid,text)->uuid.
Oid OID_FUNCTION_PROVENANCE
OID of the provenance FUNCTION.
Oid OID_FUNCTION_INVERSION_FREE_KEY
OID of provsql.inversion_free_key(text,text,int)->text.
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_FUNCTION_COND
OID of provsql.cond(uuid,uuid)->uuid.
Oid OID_TYPE_GATE_TYPE
OID of the provenance_gate TYPE.
Oid OID_FUNCTION_PROVENANCE_PROJECT
OID of the provenance_project FUNCTION.
Oid OID_FUNCTION_GET_CHILDREN
OID of the get_children FUNCTION.
Oid OID_UNNEST
OID of the unnest(anyarray) FUNCTION.
Oid OID_FUNCTION_COND_PREDICATE
cond_predicate(uuid,boolean)
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 GATE_TYPE_TO_OID[nb_gate_types]
Array of the OID of each provenance_gate ENUM value.
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_FUNCTION_AGG_COND_PREDICATE
agg_token_cond_predicate(agg_token,boolean)
Oid OID_FUNCTION_GIVEN_PREDICATE
given_predicate(boolean) – prefix whole-tuple
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_GIVEN
OID of provsql.given(uuid)->uuid.
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_FUNCTION_RV_COND
OID of provsql.random_variable_cond(random_variable,uuid).
Oid OID_FUNCTION_RV_COND_PREDICATE
random_variable_cond_predicate(random_variable,boolean)
Oid OID_TYPE_UUID_ARRAY
OID of the uuid[] TYPE.
Oid OID_FUNCTION_AGG_COND
OID of provsql.agg_token_cond(agg_token,uuid): the conditioning constructor for the agg_token carrier...
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_GET_EXTRA
OID of the get_extra FUNCTION.
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