40#include "lib/stringinfo.h"
41#include "nodes/bitmapset.h"
42#include "nodes/nodeFuncs.h"
43#include "nodes/nodes.h"
44#include "nodes/parsenodes.h"
45#include "nodes/pg_list.h"
46#if PG_VERSION_NUM >= 120000
47#include "optimizer/optimizer.h"
49#include "optimizer/tlist.h"
51#include "utils/builtins.h"
52#include "utils/lsyscache.h"
91 if (IsA(n, RangeTblRef))
93 if (IsA(n, JoinExpr)) {
94 JoinExpr *je = (JoinExpr *) n;
95 if (je->jointype != JOIN_INNER)
118 if (q->sortClause == NIL ||
119 (q->limitOffset == NULL &&
120 (q->limitCount == NULL ||
121 (IsA(q->limitCount, Const) && ((Const *) q->limitCount)->constisnull))))
126 nodes[0] = q->limitCount;
127 nodes[1] = q->limitOffset;
128 for (i = 0; i < 2; ++i) {
129 Node *n = nodes[i] ? strip_implicit_coercions(nodes[i]) : NULL;
130 if (n != NULL && IsA(n, FuncExpr) &&
158 if (q == NULL || q->commandType != CMD_SELECT) {
176 || q->hasModifyingCTE
178 || q->setOperations != NULL
179 || q->distinctClause != NIL
180 || q->groupClause != NIL
181 || q->groupingSets != NIL
182 || q->havingQual != NULL
189 if (*shape_ok && q->jointree != NULL && q->jointree->fromlist != NIL) {
190 foreach (lc, q->jointree->fromlist) {
217 foreach (lc, q->rtable) {
218 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
221 if (rte->rtekind == RTE_RELATION) {
224 *sole_relid = rte->relid;
227 }
else if (rte->rtekind == RTE_SUBQUERY) {
233 classify_walk(rte->subquery, out, shape_ok, n_meta, sole_relid);
234 }
else if (rte->rtekind == RTE_JOIN) {
259 if (IsA(node, RangeTblRef)) {
260 int rtindex = ((RangeTblRef *) node)->rtindex;
262 if (rtindex < 1 || rtindex > list_length(parent->rtable))
264 rte = (RangeTblEntry *) list_nth(parent->rtable, rtindex - 1);
265 if (rte->rtekind != RTE_SUBQUERY || rte->subquery == NULL)
267 *legs = lappend(*legs, rte->subquery);
270 if (IsA(node, SetOperationStmt)) {
271 SetOperationStmt *s = (SetOperationStmt *) node;
272 if (s->op != SETOP_UNION || !s->all)
319 if (q->setOperations == NULL || !IsA(q->setOperations, SetOperationStmt))
328 Query *leg_query = (Query *) lfirst(lc);
340 Oid relid = lfirst_oid(src_lc);
341 if (list_member_oid(seen, relid)) {
347 seen = lappend_oid(seen, relid);
387 anc_n = palloc0(n *
sizeof(uint16));
388 anc = palloc(n *
sizeof(*anc));
392 Oid relid = lfirst_oid(lc);
411 for (i = 0; i < n; i++)
412 for (j = i + 1; j < n; j++) {
414 for (a = 0; a < anc_n[i]; a++)
415 for (b = 0; b < anc_n[j]; b++)
416 if (anc[i][a] == anc[j][b]) {
440 Oid *out_relid, AttrNumber *out_attno) {
442 if (q == NULL || varno < 1
443 || (
int) varno > list_length(q->rtable))
445 rte = (RangeTblEntry *) list_nth(q->rtable, varno - 1);
446 if (rte->rtekind == RTE_RELATION) {
447 *out_relid = rte->relid;
451 if (rte->rtekind == RTE_SUBQUERY && rte->subquery != NULL) {
452 Query *sub = rte->subquery;
460 foreach (lc, sub->targetList) {
461 TargetEntry *t = (TargetEntry *) lfirst(lc);
462 if (t->resno == attno && !t->resjunk) {
469 e = (Node *) te->expr;
470 while (e != NULL && IsA(e, RelabelType))
471 e = (Node *) ((RelabelType *) e)->arg;
472 if (e == NULL || !IsA(e, Var))
475 if (v->varlevelsup != 0)
478 out_relid, out_attno);
500 foreach (lc, q->targetList) {
501 TargetEntry *te = (TargetEntry *) lfirst(lc);
502 Node *e = (Node *) te->expr;
505 AttrNumber base_attno;
508 while (e != NULL && IsA(e, RelabelType))
509 e = (Node *) ((RelabelType *) e)->arg;
510 if (e == NULL || !IsA(e, Var))
513 if (v->varlevelsup != 0)
516 &base_relid, &base_attno))
518 if (base_relid == source_relid && base_attno == bk) {
540#if PG_VERSION_NUM >= 180000
542 Index group_rtindex = 0;
544 List *groupexprs = NIL;
547 if (e == NULL || !q->hasGroupRTE)
549 foreach (lc, q->rtable) {
550 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
551 if (rte->rtekind == RTE_GROUP) {
553 groupexprs = rte->groupexprs;
558 if (group_rtindex == 0)
561 while (e != NULL && IsA(e, RelabelType))
562 e = (Node *) ((RelabelType *) e)->arg;
563 if (e == NULL || !IsA(e, Var))
566 if (v->varlevelsup != 0 || v->varno != group_rtindex)
568 if (v->varattno < 1 || v->varattno > list_length(groupexprs))
570 return (Node *) list_nth(groupexprs, v->varattno - 1);
606 Bitmapset *resolved = NULL;
609 if (q->groupClause == NIL)
611 if (q->hasAggs || q->hasWindowFuncs || q->hasTargetSRFs
612 || q->hasSubLinks || q->hasModifyingCTE || q->hasDistinctOn)
614 if (q->cteList != NIL || q->groupingSets != NIL
615 || q->havingQual != NULL || q->setOperations != NULL
616 || q->distinctClause != NIL)
618 if (q->jointree == NULL
619 || list_length(q->jointree->fromlist) != 1)
621 if (!IsA(linitial(q->jointree->fromlist), RangeTblRef))
623 rtr = (RangeTblRef *) linitial(q->jointree->fromlist);
624 if (rtr->rtindex < 1 || rtr->rtindex > list_length(q->rtable))
626 rte = (RangeTblEntry *) list_nth(q->rtable, rtr->rtindex - 1);
627 if (rte->rtekind != RTE_RELATION)
636 foreach (lc, q->groupClause) {
637 SortGroupClause *sgc = (SortGroupClause *) lfirst(lc);
641 bool attno_in_block_key =
false;
643 te = get_sortgroupclause_tle(sgc, q->targetList);
644 if (te == NULL) { bms_free(resolved);
return false; }
645 e = (Node *) te->expr;
650 while (e != NULL && IsA(e, RelabelType))
651 e = (Node *) ((RelabelType *) e)->arg;
652 if (e == NULL || !IsA(e, Var)) { bms_free(resolved);
return false; }
654 if (v->varlevelsup != 0 || v->varno != rtr->rtindex) {
655 bms_free(resolved);
return false;
659 attno_in_block_key =
true;
break;
661 if (!attno_in_block_key) { bms_free(resolved);
return false; }
662 resolved = bms_add_member(resolved, v->varattno);
666 if (!bms_is_member(info.
block_key[i], resolved)) {
667 bms_free(resolved);
return false;
677 bool shape_ok =
true;
679 Oid sole_relid = InvalidOid;
684 if (q == NULL || q->commandType != CMD_SELECT)
714 }
else if (n_meta == 0) {
718 }
else if (n_meta == 1) {
756 initStringInfo(&buf);
757 appendStringInfo(&buf,
"query result is %s",
kind_label(c->
kind));
769 appendStringInfoString(&buf,
" (no provenance-tracked sources)");
771 appendStringInfoString(&buf,
" (sources: ");
773 Oid relid = lfirst_oid(lc);
774 char *nspname = get_namespace_name(get_rel_namespace(relid));
775 char *relname = get_rel_name(relid);
778 appendStringInfoString(&buf,
", ");
781 if (nspname != NULL && relname != NULL)
782 appendStringInfo(&buf,
"%s.%s",
783 quote_identifier(nspname),
784 quote_identifier(relname));
785 else if (relname != NULL)
786 appendStringInfoString(&buf, quote_identifier(relname));
788 appendStringInfo(&buf,
"<oid %u>", relid);
790 appendStringInfoChar(&buf,
')');
provsql_table_kind
How the provenance leaves of a tracked relation are correlated.
#define PROVSQL_TABLE_INFO_MAX_ANCESTORS
Cap on the number of base ancestors recorded per relation.
static void classify_walk(Query *q, ProvSQLClassification *out, bool *shape_ok, int *n_meta, Oid *sole_relid)
Recursive walker shared by the top-level entry point and the RTE_SUBQUERY descent.
bool provsql_classify_top_level
Backing storage for the provsql.classify_top_level GUC.
static bool collect_union_all_legs(Node *node, Query *parent, List **legs)
Walk a SetOperationStmt tree, collecting each leaf leg's Query body into legs.
static bool try_classify_multi_source_tid(ProvSQLClassification *out)
Conservative multi-source promotion: when every tracked source in out->source_relids is TID and the r...
static bool bid_block_key_preserved(Query *q, Oid source_relid, const ProvenanceTableInfo *info)
Decide whether every block-key column of info survives in q's target list – resolved transitively thr...
void provsql_classify_emit_notice(const ProvSQLClassification *c)
Render the result of provsql_classify_query as a NOTICE.
static bool try_classify_groupby_block_key(Query *q, ProvSQLClassification *out)
Pre-dispatch special case for GROUP BY on a single BID source's block-key columns.
static bool try_classify_union_all(Query *q, ProvSQLClassification *out)
Promote a fully-UNION-ALL Query to TID when each leg classifies as TID and the leg source-relid sets ...
static bool limit_is_rank_filter(const Query *q)
Whether the ORDER BY ... LIMIT / OFFSET of q makes the lineage of each row depend on the rows before ...
static Node * resolve_through_group_rte(Query *q, Node *e)
PG 18+ helper: when q has a synthetic RTE_GROUP entry (set parseCheckAggregates() appends it for ever...
static bool resolve_var_to_base(Query *q, Index varno, AttrNumber attno, Oid *out_relid, AttrNumber *out_attno)
Resolve a base-level (varno, attno) pair in q transitively through RTE_SUBQUERY layers until reaching...
static bool classify_fromlist_shape_ok(Node *n)
Decide whether a jointree fromlist entry has a shape the classifier can certify : a plain RangeTblRef...
static const char * kind_label(provsql_table_kind k)
Map a provsql_table_kind to its uppercase user-facing label.
void provsql_classify_query(Query *q, ProvSQLClassification *out)
Classify the result relation of a parsed top-level Query.
Public surface of the query-time TID / BID / OPAQUE classifier.
#define provsql_notice(fmt,...)
Emit a ProvSQL informational notice (execution continues).
bool provsql_lookup_ancestry(Oid relid, uint16 *ancestor_n_out, Oid *ancestors_out)
Look up the base-ancestor set of a tracked relation.
bool provsql_lookup_table_info(Oid relid, ProvenanceTableInfo *out)
Look up per-table provenance metadata with a backend-local cache.
constants_t get_constants(bool failure_if_not_possible)
Retrieve the cached OID constants for the current database.
Core types, constants, and utilities shared across ProvSQL.
Result of provsql_classify_query.
Per-relation metadata for the safe-query optimisation.
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.
Structure to store the value of various constants.
Oid OID_FUNCTION_PLAIN
OID of the marker plain(), which keeps a LIMIT a truncation of the actual result; InvalidOid on a sch...
bool ok
true if constants were loaded