25#include "access/htup_details.h"
26#include "access/sysattr.h"
27#include "catalog/pg_aggregate.h"
28#include "catalog/pg_class.h"
29#include "catalog/pg_collation.h"
30#include "catalog/pg_operator.h"
31#include "catalog/pg_proc.h"
32#include "catalog/pg_type.h"
33#include "nodes/makefuncs.h"
34#include "utils/jsonb.h"
35#include "nodes/nodeFuncs.h"
36#include "nodes/print.h"
37#include "executor/executor.h"
38#if PG_VERSION_NUM >= 120000
39#include "optimizer/optimizer.h"
41#include "optimizer/var.h"
42#include "optimizer/clauses.h"
44#include "optimizer/planner.h"
45#include "parser/parse_coerce.h"
46#include "parser/parse_node.h"
47#include "parser/parse_oper.h"
48#include "rewrite/rewriteManip.h"
49#include "parser/parse_relation.h"
50#include "utils/builtins.h"
51#if PG_VERSION_NUM >= 120000
52#include "utils/float.h"
54#include "parser/parsetree.h"
55#include "storage/lwlock.h"
56#include "storage/shmem.h"
57#include "utils/fmgroids.h"
59#include "utils/lsyscache.h"
60#include "utils/ruleutils.h"
61#include "utils/syscache.h"
62#include "catalog/namespace.h"
63#include "catalog/pg_cast.h"
64#include "commands/createas.h"
65#include "executor/spi.h"
66#include "tcop/utility.h"
67#include "tcop/tcopprot.h"
77#if PG_VERSION_NUM < 100000
78#error "ProvSQL requires PostgreSQL version 10 or later"
150 bool **removed,
bool wrap_root,
bool top_level,
151 bool in_boolean_rewrite,
178 RangeTblEntry *r, Index relid,
180 Var *v = makeNode(Var);
185#if PG_VERSION_NUM >= 130000
187 v->varattnosyn = attid;
190 v->varoattno = attid;
194 v->varcollid = InvalidOid;
198#if PG_VERSION_NUM >= 160000
199 if (r->perminfoindex != 0) {
200 RTEPermissionInfo *rpi =
201 list_nth_node(RTEPermissionInfo, q->rteperminfos, r->perminfoindex - 1);
202 rpi->selectedCols = bms_add_member(
203 rpi->selectedCols, attid - FirstLowInvalidHeapAttributeNumber);
206 r->selectedCols = bms_add_member(r->selectedCols,
207 attid - FirstLowInvalidHeapAttributeNumber);
234 if (IsA(node, Var)) {
235 Var *v = (Var *)node;
237 if (v->varno == context->
varno) {
238 v->varattno += context->
offset[v->varattno - 1];
262 foreach (lc, targetList) {
263 Node *te = lfirst(lc);
280 if (IsA(node, Var)) {
281 Var *v = (Var *)node;
282 return v->varno == context->
varno && v->varattno == context->
varattno;
308 if (IsA(node, FuncExpr)) {
309 FuncExpr *f = (FuncExpr *)node;
312 if (list_length(f->args) == 1 &&
315 HeapTuple castTuple = SearchSysCache2(CASTSOURCETARGET,
317 ObjectIdGetDatum(f->funcresulttype));
319 if (HeapTupleIsValid(castTuple)) {
320 Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(castTuple);
321 if (OidIsValid(castForm->castfunc)) {
322 f->funcid = castForm->castfunc;
324 ReleaseSysCache(castTuple);
328 ((Var *)linitial(f->args))->vartype =
335 if (IsA(node, Var)) {
336 Var *v = (Var *)node;
338 if (v->varno == context->
varno && v->varattno == context->
varattno) {
371 Query *q, Index rteid,
377 foreach (lc, targetList) {
378 TargetEntry *te = (TargetEntry *)lfirst(lc);
381 context.
varno = rteid;
384 QTW_DONT_COPY_QUERY | QTW_IGNORE_RC_SUBQUERIES);
389 foreach (lc2, q->targetList) {
390 TargetEntry *outer_te = (TargetEntry *)lfirst(lc2);
391 if (IsA(outer_te->expr, Var)) {
392 Var *v = (Var *)outer_te->expr;
393 if (v->varno == rteid && v->varattno == attno &&
394 outer_te->ressortgroupref > 0) {
396 foreach (lc3, q->sortClause) {
397 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc3);
398 if (sgc->tleSortGroupRef == outer_te->ressortgroupref)
400 "a subquery not supported");
402 foreach (lc3, q->groupClause) {
403 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc3);
404 if (sgc->tleSortGroupRef == outer_te->ressortgroupref)
406 "a subquery not supported");
431#if PG_VERSION_NUM >= 150000
438 const char *src_name;
439 const char *dst_name;
440 const char *source_text;
442 const char *source_attname;
444 const char *edge_quals;
445 const char *edge_sql;
449#if PG_VERSION_NUM >= 150000
451static Query *lookup_lowered_cte(List *lowered,
const char *name) {
453 foreach (lc, lowered) {
455 if (strcmp(e->
name, name) == 0)
462#if PG_VERSION_NUM >= 150000
464typedef struct ReachabilityShape {
466 AttrNumber src_attno;
467 AttrNumber dst_attno;
470 AttrNumber source_attno;
474 List *edge_rte_colnames;
482typedef struct ReachVarnosCtx {
488static bool reach_varnos_walker(Node *node, ReachVarnosCtx *ctx) {
491 if (IsA(node, Var)) {
492 Var *v = (Var *) node;
493 if (v->varlevelsup != 0)
496 ctx->varnos = bms_add_member(ctx->varnos, v->varno);
499 return expression_tree_walker(node, reach_varnos_walker, (
void *) ctx);
503static Node *reach_strip(Node *n) {
504 while (n != NULL && IsA(n, RelabelType))
505 n = (Node *) ((RelabelType *) n)->arg;
514static void reach_collect_quals(Node *jtnode, List **quals,
bool *ok) {
515 if (jtnode == NULL || !*ok)
517 if (IsA(jtnode, FromExpr)) {
518 FromExpr *f = (FromExpr *) jtnode;
520 foreach(lc, f->fromlist)
521 reach_collect_quals((Node *) lfirst(lc), quals, ok);
523 *quals = list_concat(*quals, make_ands_implicit((Expr *) f->quals));
524 }
else if (IsA(jtnode, JoinExpr)) {
525 JoinExpr *j = (JoinExpr *) jtnode;
526 if (j->jointype != JOIN_INNER) {
530 reach_collect_quals(j->larg, quals, ok);
531 reach_collect_quals(j->rarg, quals, ok);
533 *quals = list_concat(*quals, make_ands_implicit((Expr *) j->quals));
539static TargetEntry *reach_single_tle(Query *q) {
540 TargetEntry *res = NULL;
542 foreach(lc, q->targetList) {
543 TargetEntry *te = (TargetEntry *) lfirst(lc);
554static bool reach_two_tles(Query *q, TargetEntry *out[2]) {
556 out[0] = out[1] = NULL;
557 foreach(lc, q->targetList) {
558 TargetEntry *te = (TargetEntry *) lfirst(lc);
561 if (te->resno < 1 || te->resno > 2 || out[te->resno - 1] != NULL)
563 out[te->resno - 1] = te;
565 return out[0] != NULL && out[1] != NULL;
569static bool reach_int_const(Node *n, int64 *value) {
570 Const *c = (Const *) reach_strip(n);
571 if (c == NULL || !IsA(c, Const) || c->constisnull)
573 switch (c->consttype) {
575 *value = DatumGetInt16(c->constvalue);
578 *value = DatumGetInt32(c->constvalue);
581 *value = DatumGetInt64(c->constvalue);
593static bool reach_is_hop_increment(Node *n, Index cte_rti, AttrNumber resno) {
594 OpExpr *op = (OpExpr *) reach_strip(n);
599 if (op == NULL || !IsA(op, OpExpr) || list_length(op->args) != 2)
601 opname = get_opname(op->opno);
602 is_plus = opname != NULL && strcmp(opname,
"+") == 0;
607 if (reach_int_const((Node *) lsecond(op->args), &one))
608 v = (Var *) reach_strip((Node *) linitial(op->args));
609 else if (reach_int_const((Node *) linitial(op->args), &one))
610 v = (Var *) reach_strip((Node *) lsecond(op->args));
613 if (one != 1 || v == NULL || !IsA(v, Var))
615 return v->varno == cte_rti && v->varlevelsup == 0 && v->varattno == resno;
623static bool reach_is_hop_bound(Node *n, Index cte_rti, AttrNumber hops_pos,
624 int64 *bound,
bool *strict) {
625 OpExpr *op = (OpExpr *) reach_strip(n);
629 if (op == NULL || !IsA(op, OpExpr) || list_length(op->args) != 2)
631 v = (Var *) reach_strip((Node *) linitial(op->args));
632 if (v != NULL && IsA(v, Var) &&
633 reach_int_const((Node *) lsecond(op->args), bound))
636 v = (Var *) reach_strip((Node *) lsecond(op->args));
637 if (v == NULL || !IsA(v, Var) ||
638 !reach_int_const((Node *) linitial(op->args), bound))
642 if (v->varno != cte_rti || v->varlevelsup != 0 || v->varattno != hops_pos)
644 opname = get_opname(op->opno);
648 if (strcmp(opname, var_first ?
"<" :
">") == 0)
650 else if (strcmp(opname, var_first ?
"<=" :
">=") == 0)
698static bool detect_reachability_cte(CommonTableExpr *cte, Query *cteq,
700 ReachabilityShape *out) {
701 SetOperationStmt *so = (SetOperationStmt *) cteq->setOperations;
703 Query *base = NULL, *rec = NULL;
704 Index edge_rti = 0, cte_rti = 0;
711 Var *va, *vb, *edge_var, *cte_var;
712 AttrNumber prov_attno;
716 AttrNumber node_pos = 1, hops_pos = 0;
717 TargetEntry *base_tles[2], *rec_tles[2];
720 if (list_length(cte->ctecolnames) == 1)
722 else if (list_length(cte->ctecolnames) == 2)
727 if (!IsA(so->larg, RangeTblRef) || !IsA(so->rarg, RangeTblRef))
729 for (i = 0; i < 2; ++i) {
730 RangeTblRef *rtr = (RangeTblRef *) (i == 0 ? so->larg : so->rarg);
731 RangeTblEntry *r = rt_fetch(rtr->rtindex, cteq->rtable);
732 if (r->rtekind != RTE_SUBQUERY || r->subquery == NULL)
734 arms[i] = r->subquery;
740 Index rec_self_rti = 0;
741 for (i = 0; i < 2; ++i) {
742 bool has_self =
false;
743 Index rti = 0, self_rti = 0;
744 foreach(lc, arms[i]->rtable) {
745 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
747 if (r->rtekind == RTE_CTE && r->self_reference &&
748 strcmp(r->ctename, cte->ctename) == 0) {
757 rec_self_rti = self_rti;
764 if (base == NULL || rec == NULL)
773 if (!reach_two_tles(rec, rec_tles) || !reach_two_tles(base, base_tles))
775 for (i = 0; i < 2; ++i)
776 if (reach_is_hop_increment((Node *) rec_tles[i]->expr, rec_self_rti,
777 (AttrNumber) (i + 1))) {
778 hops_pos = (AttrNumber) (i + 1);
783 node_pos = (AttrNumber) (3 - hops_pos);
784 if (!reach_int_const((Node *) base_tles[hops_pos - 1]->expr, &hop_seed))
786 if (hop_seed < PG_INT32_MIN/2 || hop_seed > PG_INT32_MAX/2)
794 if (base->setOperations != NULL || base->hasAggs || base->hasSubLinks ||
795 base->hasTargetSRFs || base->groupClause != NIL ||
796 base->distinctClause != NIL || base->jointree == NULL ||
797 base->jointree->quals != NULL)
799 tle = hops_mode ? base_tles[node_pos - 1] : reach_single_tle(base);
802 if (base->jointree->fromlist == NIL) {
803 Node *bexpr = reach_strip((Node *) tle->expr);
807 if (bexpr == NULL || !IsA(bexpr, Const))
812 getTypeOutputInfo(c->consttype, &outfunc, &varlena);
813 out->source_text = OidOutputFunctionCall(outfunc, c->constvalue);
815 RangeTblEntry *srel = NULL;
819 if (list_length(base->jointree->fromlist) != 1 ||
820 !IsA(linitial(base->jointree->fromlist), RangeTblRef))
822 foreach(lc, base->rtable) {
823 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
825 if (r->rtekind != RTE_RELATION || r->relkind != RELKIND_RELATION)
834 sv = (Var *) reach_strip((Node *) tle->expr);
835 if (sv == NULL || !IsA(sv, Var) || sv->varno != srel_rti ||
836 sv->varlevelsup != 0 || sv->varattno <= 0)
841 if (sprov != InvalidAttrNumber && sv->varattno == sprov)
844 out->source_relid = srel->relid;
845 out->source_attno = sv->varattno;
849 if (rec->hasAggs || rec->hasWindowFuncs || rec->hasSubLinks ||
850 rec->hasTargetSRFs || rec->groupClause != NIL ||
851 rec->distinctClause != NIL || rec->sortClause != NIL ||
852 rec->havingQual != NULL || rec->limitOffset != NULL ||
853 rec->limitCount != NULL || rec->setOperations != NULL ||
854 rec->groupingSets != NIL)
858 RangeTblEntry *edge_rte = NULL;
859 foreach(lc, rec->rtable) {
860 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
862 switch (r->rtekind) {
864 if (edge_rti != 0 || r->relkind != RELKIND_RELATION)
868 out->relid = r->relid;
876 if (edge_rti != 0 || r->subquery == NULL)
880 out->relid = InvalidOid;
881 out->edge_sql = pg_get_querydef(copyObject(r->subquery),
false);
884 if (cte_rti != 0 || !r->self_reference ||
885 strcmp(r->ctename, cte->ctename) != 0)
895 if (edge_rti == 0 || cte_rti == 0)
898 if (OidIsValid(out->relid)) {
902 if (prov_attno == InvalidAttrNumber ||
903 get_atttype(out->relid, prov_attno) != constants->OID_TYPE_UUID)
906 prov_attno = InvalidAttrNumber;
908 out->edge_rte_colnames = edge_rte->eref->colnames;
916 reach_collect_quals((Node *) rec->jointree, &quals, &ok);
920 List *edge_only = NIL;
921 bool have_bound =
false;
926 Node *q = (Node *) lfirst(lc);
927 ReachVarnosCtx vctx = {NULL,
false};
928 reach_varnos_walker(q, &vctx);
931 if (bms_is_member(cte_rti, vctx.varnos)) {
934 if (hops_mode && !have_bound &&
935 reach_is_hop_bound(q, cte_rti, hops_pos, &bound, &strict))
937 else if (join_qual == NULL)
941 }
else if (bms_is_subset(vctx.varnos, bms_make_singleton(edge_rti))) {
944 if (contain_volatile_functions(q))
946 edge_only = lappend(edge_only, q);
950 if (join_qual == NULL)
959 max_len = bound - hop_seed + (strict ? 0 : 1);
964 out->hop_bound = (int) max_len;
965 out->hop_seed = (int) hop_seed;
966 out->hops_position = hops_pos;
968 out->node_position = node_pos;
969 if (edge_only != NIL && !OidIsValid(out->relid))
971 if (edge_only != NIL) {
974 Node *conj = (Node *) make_ands_explicit(edge_only);
976 conj = copyObject(conj);
977 ChangeVarNodes(conj, edge_rti, 1, 0);
978 dpcontext = deparse_context_for(get_rel_name(out->relid), out->relid);
979 out->edge_quals = deparse_expression(conj, dpcontext,
false,
false);
984 tle = hops_mode ? rec_tles[node_pos - 1] : reach_single_tle(rec);
988 Node *texpr = reach_strip((Node *) tle->expr);
989 if (texpr != NULL && IsA(texpr, Var)) {
990 target_var = (Var *) texpr;
991 if (target_var->varno != edge_rti || target_var->varlevelsup != 0 ||
992 target_var->varattno <= 0 || target_var->varattno == prov_attno)
994 out->dst_attno = target_var->varattno;
996 if (!IsA(join_qual, OpExpr))
998 eq = (OpExpr *) join_qual;
999 if (list_length(eq->args) != 2)
1001 va = (Var *) reach_strip((Node *) linitial(eq->args));
1002 vb = (Var *) reach_strip((Node *) lsecond(eq->args));
1003 if (va == NULL || vb == NULL || !IsA(va, Var) || !IsA(vb, Var) ||
1004 va->varlevelsup != 0 || vb->varlevelsup != 0)
1006 if (!op_mergejoinable(eq->opno, exprType((Node *) linitial(eq->args))))
1008 if (va->varno == edge_rti && vb->varno == cte_rti)
1009 edge_var = va, cte_var = vb;
1010 else if (vb->varno == edge_rti && va->varno == cte_rti)
1011 edge_var = vb, cte_var = va;
1014 if (cte_var->varattno != node_pos || edge_var->varattno <= 0 ||
1015 edge_var->varattno == prov_attno)
1017 out->src_attno = edge_var->varattno;
1018 out->directed =
true;
1027 if (texpr != NULL && IsA(texpr, CaseExpr)) {
1028 CaseExpr *ce = (CaseExpr *) texpr;
1031 Var *wa, *wb, *wedge, *wcte, *res, *def;
1032 AttrNumber col_a, col_b;
1034 if (ce->arg != NULL || list_length(ce->args) != 1 ||
1035 ce->defresult == NULL)
1037 cw = (CaseWhen *) linitial(ce->args);
1038 if (!IsA(cw->expr, OpExpr))
1040 weq = (OpExpr *) cw->expr;
1041 if (list_length(weq->args) != 2 ||
1042 !op_mergejoinable(weq->opno, exprType((Node *) linitial(weq->args))))
1044 wa = (Var *) reach_strip((Node *) linitial(weq->args));
1045 wb = (Var *) reach_strip((Node *) lsecond(weq->args));
1046 if (wa == NULL || wb == NULL || !IsA(wa, Var) || !IsA(wb, Var) ||
1047 wa->varlevelsup != 0 || wb->varlevelsup != 0)
1049 if (wa->varno == edge_rti && wb->varno == cte_rti)
1050 wedge = wa, wcte = wb;
1051 else if (wb->varno == edge_rti && wa->varno == cte_rti)
1052 wedge = wb, wcte = wa;
1055 if (wcte->varattno != node_pos)
1057 res = (Var *) reach_strip((Node *) cw->result);
1058 def = (Var *) reach_strip((Node *) ce->defresult);
1059 if (res == NULL || def == NULL || !IsA(res, Var) || !IsA(def, Var) ||
1060 res->varno != edge_rti || def->varno != edge_rti ||
1061 res->varlevelsup != 0 || def->varlevelsup != 0)
1065 col_a = wedge->varattno;
1066 col_b = res->varattno;
1067 if (def->varattno != col_a || col_a == col_b ||
1068 col_a <= 0 || col_b <= 0 ||
1069 col_a == prov_attno || col_b == prov_attno)
1074 AttrNumber got[2] = {0, 0};
1076 if (IsA(join_qual, BoolExpr) &&
1077 ((BoolExpr *) join_qual)->boolop == OR_EXPR &&
1078 list_length(((BoolExpr *) join_qual)->args) == 2) {
1080 foreach(olc, ((BoolExpr *) join_qual)->args) {
1081 OpExpr *oeq = (OpExpr *) lfirst(olc);
1082 Var *oa, *ob, *oedge, *octe;
1083 if (!IsA(oeq, OpExpr) || list_length(oeq->args) != 2 ||
1084 !op_mergejoinable(oeq->opno,
1085 exprType((Node *) linitial(oeq->args))))
1087 oa = (Var *) reach_strip((Node *) linitial(oeq->args));
1088 ob = (Var *) reach_strip((Node *) lsecond(oeq->args));
1089 if (oa == NULL || ob == NULL || !IsA(oa, Var) || !IsA(ob, Var))
1091 if (oa->varno == edge_rti && ob->varno == cte_rti)
1092 oedge = oa, octe = ob;
1093 else if (ob->varno == edge_rti && oa->varno == cte_rti)
1094 oedge = ob, octe = oa;
1097 if (octe->varattno != node_pos || n >= 2)
1099 got[n++] = oedge->varattno;
1101 }
else if (IsA(join_qual, ScalarArrayOpExpr)) {
1102 ScalarArrayOpExpr *sao = (ScalarArrayOpExpr *) join_qual;
1106 if (!sao->useOr || list_length(sao->args) != 2 ||
1107 !op_mergejoinable(sao->opno,
1108 exprType((Node *) linitial(sao->args))))
1110 scte = (Var *) reach_strip((Node *) linitial(sao->args));
1111 if (scte == NULL || !IsA(scte, Var) || scte->varno != cte_rti ||
1112 scte->varattno != node_pos)
1114 arr = (ArrayExpr *) reach_strip((Node *) lsecond(sao->args));
1115 if (arr == NULL || !IsA(arr, ArrayExpr) ||
1116 list_length(arr->elements) != 2)
1118 foreach(alc, arr->elements) {
1119 Var *ev = (Var *) reach_strip((Node *) lfirst(alc));
1120 if (ev == NULL || !IsA(ev, Var) || ev->varno != edge_rti ||
1123 got[n++] = ev->varattno;
1128 !((got[0] == col_a && got[1] == col_b) ||
1129 (got[0] == col_b && got[1] == col_a)))
1133 out->src_attno = col_a;
1134 out->dst_attno = col_b;
1135 out->directed =
false;
1143#if PG_VERSION_NUM >= 150000
1164static bool lower_recursive_cte(CommonTableExpr *cte, RangeTblEntry *r,
1166 Query *cteq = (Query *) cte->ctequery;
1168 StringInfoData cols, coldef, call, scan;
1169 ListCell *lcn, *lct;
1173 if (cteq == NULL || !IsA(cteq, Query))
1180 if (cteq->setOperations == NULL ||
1181 !IsA(cteq->setOperations, SetOperationStmt) ||
1182 ((SetOperationStmt *) cteq->setOperations)->op != SETOP_UNION ||
1183 ((SetOperationStmt *) cteq->setOperations)->all)
1195 foreach(lc, cteq->rtable) {
1196 RangeTblEntry *sub = (RangeTblEntry *) lfirst(lc);
1197 if (sub->rtekind == RTE_SUBQUERY && sub->subquery != NULL &&
1198 sub->subquery->hasTargetSRFs)
1205 body_text = pg_get_querydef(cteq,
false);
1208 initStringInfo(&cols);
1209 initStringInfo(&coldef);
1210 forboth(lcn, cte->ctecolnames, lct, cte->ctecoltypes) {
1211 char *name = strVal(lfirst(lcn));
1212 Oid typid = lfirst_oid(lct);
1214 appendStringInfoString(&cols,
", ");
1215 appendStringInfoString(&coldef,
", ");
1218 appendStringInfoString(&cols, quote_identifier(name));
1219 appendStringInfo(&coldef,
"%s %s", quote_identifier(name), format_type_be(typid));
1223 provsql_notice(
"Lowering recursive CTE '%s':\n body = %s\n coldef = %s",
1224 cte->ctename, body_text, coldef.data);
1239 initStringInfo(&call);
1241 ReachabilityShape shape = {InvalidOid, 0, 0, NULL, InvalidOid, 0,
true,
1242 NULL, NULL, NIL, -1, 0, 0, 1};
1245 detect_reachability_cte(cte, cteq, &constants, &shape)) {
1248 char *coltype = format_type_be(
1249 list_nth_oid(cte->ctecoltypes, shape.node_position - 1));
1250 StringInfoData relarg;
1251 if (OidIsValid(shape.relid)) {
1252 src_name = get_attname(shape.relid, shape.src_attno,
false);
1253 dst_name = get_attname(shape.relid, shape.dst_attno,
false);
1255 src_name = strVal(list_nth(shape.edge_rte_colnames,
1256 shape.src_attno - 1));
1257 dst_name = strVal(list_nth(shape.edge_rte_colnames,
1258 shape.dst_attno - 1));
1260 initStringInfo(&relarg);
1261 if (OidIsValid(shape.relid))
1262 appendStringInfo(&relarg,
"%u::pg_catalog.regclass", shape.relid);
1264 appendStringInfoString(&relarg,
"NULL::pg_catalog.regclass");
1266 provsql_notice(
"Recursive CTE '%s' recognised as reachability over %s",
1268 OidIsValid(shape.relid) ? get_rel_name(shape.relid)
1269 :
"a join-defined edge query");
1273 if (entry != NULL && shape.hop_bound < 0) {
1274 entry->reach_routed =
true;
1275 entry->edge_relid = shape.relid;
1276 entry->src_name = pstrdup(src_name);
1277 entry->dst_name = pstrdup(dst_name);
1278 entry->source_text =
1279 shape.source_text ? pstrdup(shape.source_text) : NULL;
1280 entry->source_relid = shape.source_relid;
1281 entry->source_attname =
1282 OidIsValid(shape.source_relid)
1283 ? get_attname(shape.source_relid, shape.source_attno,
false)
1285 entry->directed = shape.directed;
1287 shape.edge_quals ? pstrdup(shape.edge_quals) : NULL;
1288 entry->edge_sql = shape.edge_sql ? pstrdup(shape.edge_sql) : NULL;
1290 appendStringInfo(&call,
1291 "SELECT provsql.eval_reachability(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
1293 quote_literal_cstr(src_name),
1294 quote_literal_cstr(dst_name),
1296 ? quote_literal_cstr(shape.source_text) :
"NULL",
1297 shape.directed ?
"true" :
"false",
1298 quote_literal_cstr(cte->ctename),
1299 quote_literal_cstr(cols.data),
1300 quote_literal_cstr(coldef.data),
1301 quote_literal_cstr(coltype),
1302 quote_literal_cstr(body_text),
1304 ? quote_literal_cstr(shape.edge_quals) :
"NULL");
1305 if (OidIsValid(shape.source_relid)) {
1306 char *satt = get_attname(shape.source_relid, shape.source_attno,
1308 appendStringInfo(&call,
", %u::pg_catalog.regclass, %s",
1309 shape.source_relid, quote_literal_cstr(satt));
1310 }
else if (shape.edge_sql != NULL)
1311 appendStringInfoString(&call,
", NULL, NULL");
1312 if (shape.edge_sql != NULL)
1313 appendStringInfo(&call,
", %s", quote_literal_cstr(shape.edge_sql));
1314 if (shape.hop_bound >= 0)
1315 appendStringInfo(&call,
1316 ", hop_bound => %d, hop_seed => %d, hops_position => %d",
1317 shape.hop_bound, shape.hop_seed,
1318 shape.hops_position);
1319 appendStringInfoString(&call,
")");
1321 appendStringInfo(&call,
"SELECT provsql.eval_recursive(%s, %s, %s, %s)",
1322 quote_literal_cstr(body_text),
1323 quote_literal_cstr(cte->ctename),
1324 quote_literal_cstr(cols.data),
1325 quote_literal_cstr(coldef.data));
1328 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
1329 provsql_error(
"Recursive CTE lowering: SPI_connect failed (%d)", rc);
1330 rc = SPI_execute(call.data,
false, 0);
1333 provsql_error(
"Recursive CTE lowering: eval_recursive failed (%d)", rc);
1336 initStringInfo(&scan);
1337 appendStringInfo(&scan,
"SELECT %s FROM %s",
1338 cols.data, quote_identifier(cte->ctename));
1340 List *raw = pg_parse_query(scan.data);
1341 List *analyzed = pg_analyze_and_rewrite_fixedparams(
1342 linitial_node(RawStmt, raw), scan.data, NULL, 0, NULL);
1343 r->rtekind = RTE_SUBQUERY;
1344 r->subquery = linitial_node(Query, analyzed);
1371 if (IsA(node, Query)) {
1372 Query *sub = (Query *)node;
1374 foreach (lc, sub->rtable) {
1375 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
1376 if (r->rtekind == RTE_CTE && r->ctename != NULL &&
1377 strcmp(r->ctename, ctx->
name) == 0)
1412 foreach (lc, rtable) {
1413 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
1414 if (r->rtekind == RTE_CTE) {
1416 foreach (lc2, cteList) {
1417 CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc2);
1418 if (strcmp(cte->ctename, r->ctename) == 0) {
1419 if (list_member_ptr(kept, cte)) {
1423 }
else if (cte->cterecursive) {
1424#if PG_VERSION_NUM >= 150000
1430 Query *memo = lookup_lowered_cte(*lowered, cte->ctename);
1432 r->rtekind = RTE_SUBQUERY;
1433 r->subquery = copyObject(memo);
1438 if (lower_recursive_cte(cte, r, e)) {
1441 e->
name = pstrdup(cte->ctename);
1442 e->
subquery = copyObject(r->subquery);
1443 *lowered = lappend(*lowered, e);
1446 provsql_error(
"Recursive CTEs not supported (unsupported recursion shape)");
1452 r->rtekind = RTE_SUBQUERY;
1453 r->subquery = copyObject((Query *)cte->ctequery);
1463 }
else if (r->rtekind == RTE_SUBQUERY && r->subquery != NULL) {
1471#if PG_VERSION_NUM >= 150000
1476} ReachMemberQualCtx;
1484static bool reach_member_local_walker(Node *node, ReachMemberQualCtx *ctx) {
1487 if (IsA(node, Var)) {
1488 Var *v = (Var *) node;
1489 if (v->varlevelsup != 0 || v->varno != ctx->t_rti)
1493 if (IsA(node, SubLink) || IsA(node, Param)) {
1497 return expression_tree_walker(node, reach_member_local_walker, ctx);
1505static bool reach_member_local_qual(Node *qual, Index t_rti) {
1506 ReachMemberQualCtx ctx = { t_rti,
true };
1507 reach_member_local_walker(qual, &ctx);
1512typedef struct ReachAggCandidate {
1513 const char *ctename;
1514 const char *node_colname;
1516 const char *member_attname;
1517 const char *group_attname;
1518 const char *member_quals;
1543static List *detect_reach_aggregations(Query *q) {
1546 Index rti = 0, cte_rti = 0, t_rti = 0;
1547 RangeTblEntry *cte_rte = NULL, *t_rte = NULL;
1548 SortGroupClause *sgc;
1549 TargetEntry *gtle = NULL;
1552 List *member_quals = NIL;
1555 Var *cte_var, *t_var;
1556 CommonTableExpr *cte = NULL;
1557 ReachAggCandidate *cand;
1559 if (q->setOperations != NULL || list_length(q->groupClause) != 1 ||
1560 q->groupingSets != NIL || q->cteList == NIL)
1563 foreach(lc, q->rtable) {
1564 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1566 switch (r->rtekind) {
1568 if (cte_rti != 0 || r->ctelevelsup != 0)
1574 if (t_rti != 0 || r->relkind != RELKIND_RELATION)
1580#if PG_VERSION_NUM >= 180000
1589 if (cte_rti == 0 || t_rti == 0)
1595 foreach(lc, q->cteList) {
1596 CommonTableExpr *c = (CommonTableExpr *) lfirst(lc);
1597 if (strcmp(c->ctename, cte_rte->ctename) == 0) {
1602 if (cte == NULL || !cte->cterecursive ||
1603 list_length(cte->ctecolnames) != 1)
1607 sgc = (SortGroupClause *) linitial(q->groupClause);
1608 foreach(lc, q->targetList) {
1609 TargetEntry *te = (TargetEntry *) lfirst(lc);
1610 if (te->ressortgroupref == sgc->tleSortGroupRef) {
1617 gvar = (Var *) reach_strip((Node *) gtle->expr);
1618#if PG_VERSION_NUM >= 180000
1621 if (q->hasGroupRTE && gvar != NULL && IsA(gvar, Var) &&
1622 gvar->varlevelsup == 0) {
1624 foreach(lc, q->rtable) {
1625 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1626 if (r->rtekind == RTE_GROUP) {
1627 if (gvar->varno == gidx && gvar->varattno >= 1 &&
1628 gvar->varattno <= list_length(r->groupexprs))
1629 gvar = (Var *) reach_strip(
1630 (Node *) list_nth(r->groupexprs, gvar->varattno - 1));
1637 if (gvar == NULL || !IsA(gvar, Var) || gvar->varno != t_rti ||
1638 gvar->varlevelsup != 0 || gvar->varattno <= 0)
1647 cte_var = t_var = NULL;
1648 reach_collect_quals((Node *) q->jointree, &quals, &ok);
1649 if (!ok || quals == NIL)
1651 foreach(lc, quals) {
1652 Node *qual = (Node *) lfirst(lc);
1655 if (cte_var == NULL && IsA(qual, OpExpr)) {
1656 eq = (OpExpr *) qual;
1657 if (list_length(eq->args) == 2 &&
1658 op_mergejoinable(eq->opno, exprType((Node *) linitial(eq->args)))) {
1659 Var *ja = (Var *) reach_strip((Node *) linitial(eq->args));
1660 Var *jb = (Var *) reach_strip((Node *) lsecond(eq->args));
1661 if (ja != NULL && jb != NULL && IsA(ja, Var) && IsA(jb, Var) &&
1662 ja->varlevelsup == 0 && jb->varlevelsup == 0) {
1663 if (ja->varno == cte_rti && jb->varno == t_rti) {
1667 }
else if (jb->varno == cte_rti && ja->varno == t_rti) {
1677 if (!reach_member_local_qual(qual, t_rti) ||
1678 contain_volatile_functions(qual))
1680 member_quals = lappend(member_quals, qual);
1682 if (cte_var == NULL)
1684 if (cte_var->varattno != 1 || t_var->varattno <= 0)
1687 cand = (ReachAggCandidate *) palloc(
sizeof(ReachAggCandidate));
1688 cand->ctename = pstrdup(cte->ctename);
1689 cand->node_colname = pstrdup(strVal(linitial(cte->ctecolnames)));
1690 cand->member_relid = t_rte->relid;
1691 cand->member_attname = get_attname(t_rte->relid, t_var->varattno,
false);
1692 cand->group_attname = get_attname(t_rte->relid, gvar->varattno,
false);
1693 cand->member_quals = NULL;
1694 if (member_quals != NIL) {
1700 Node *conj = (Node *) make_ands_explicit(member_quals);
1702 conj = copyObject(conj);
1703 ChangeVarNodes(conj, t_rti, 1, 0);
1704 dpcontext = deparse_context_for(
"t", t_rte->relid);
1705 cand->member_quals = deparse_expression(conj, dpcontext,
true,
false);
1707 out = lappend(out, cand);
1718static void plant_reach_aggregations(List *candidates, List *lowered) {
1720 foreach(lc, candidates) {
1721 ReachAggCandidate *cand = (ReachAggCandidate *) lfirst(lc);
1724 StringInfoData call;
1726 foreach(ll, lowered) {
1728 if (strcmp(e->
name, cand->ctename) == 0) {
1733 if (entry == NULL || !entry->reach_routed)
1736 initStringInfo(&call);
1737 appendStringInfo(&call,
1738 "SELECT provsql.plant_reach_any_groups(%s, %s, %u::pg_catalog.regclass, %s, %s, ",
1739 quote_literal_cstr(cand->ctename),
1740 quote_literal_cstr(cand->node_colname),
1742 quote_literal_cstr(cand->member_attname),
1743 quote_literal_cstr(cand->group_attname));
1744 if (OidIsValid(entry->edge_relid))
1745 appendStringInfo(&call,
"%u::pg_catalog.regclass", entry->edge_relid);
1747 appendStringInfoString(&call,
"NULL::pg_catalog.regclass");
1748 appendStringInfo(&call,
", %s, %s, %s, %s, %s, ",
1749 quote_literal_cstr(entry->src_name),
1750 quote_literal_cstr(entry->dst_name),
1752 ? quote_literal_cstr(entry->source_text) :
"NULL",
1753 entry->directed ?
"true" :
"false",
1755 ? quote_literal_cstr(entry->edge_quals) :
"NULL");
1756 if (OidIsValid(entry->source_relid))
1757 appendStringInfo(&call,
"%u::pg_catalog.regclass, %s, ",
1758 entry->source_relid,
1759 quote_literal_cstr(entry->source_attname));
1761 appendStringInfoString(&call,
"NULL, NULL, ");
1762 appendStringInfo(&call,
"%s, %s)",
1764 ? quote_literal_cstr(entry->edge_sql) :
"NULL",
1766 ? quote_literal_cstr(cand->member_quals) :
"NULL");
1768 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
1769 provsql_error(
"Reachability aggregation planting: SPI_connect failed (%d)", rc);
1770 rc = SPI_execute(call.data,
false, 0);
1773 provsql_error(
"Reachability aggregation planting failed (%d)", rc);
1778typedef struct ReachConjCandidate {
1779 const char *ctename;
1780 const char *node_colname;
1783} ReachConjCandidate;
1810static List *detect_reach_conjunctions(Query *q) {
1814 RangeTblEntry *cte_rte = NULL;
1815 CommonTableExpr *cte = NULL;
1819 List *const_texts = NIL;
1820 ReachConjCandidate *cand;
1822 if (q->setOperations != NULL || q->groupClause != NIL ||
1823 q->groupingSets != NIL || q->distinctClause != NIL ||
1824 q->havingQual != NULL || q->hasAggs || q->hasWindowFuncs ||
1825 q->hasSubLinks || q->cteList == NIL)
1828 foreach(lc, q->rtable) {
1829 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1831 switch (r->rtekind) {
1833 if (r->ctelevelsup != 0)
1835 if (cte_rte == NULL)
1837 else if (strcmp(cte_rte->ctename, r->ctename) != 0)
1852 foreach(lc, q->cteList) {
1853 CommonTableExpr *c = (CommonTableExpr *) lfirst(lc);
1854 if (strcmp(c->ctename, cte_rte->ctename) == 0) {
1859 if (cte == NULL || !cte->cterecursive ||
1860 list_length(cte->ctecolnames) != 1)
1865 reach_collect_quals((Node *) q->jointree, &quals, &ok);
1866 if (!ok || list_length(quals) != nb_refs)
1868 bound = (Node **) palloc0(
sizeof(Node *) * (list_length(q->rtable) + 1));
1869 foreach(lc, quals) {
1874 if (!IsA(lfirst(lc), OpExpr))
1876 eq = (OpExpr *) lfirst(lc);
1877 if (list_length(eq->args) != 2 ||
1878 !op_mergejoinable(eq->opno, exprType((Node *) linitial(eq->args))))
1880 na = reach_strip((Node *) linitial(eq->args));
1881 nb = reach_strip((Node *) lsecond(eq->args));
1882 if (na != NULL && IsA(na, Var) && nb != NULL && IsA(nb, Const)) {
1885 }
else if (nb != NULL && IsA(nb, Var) && na != NULL && IsA(na, Const)) {
1890 if (v->varlevelsup != 0 || v->varattno != 1 ||
1891 v->varno < 1 || v->varno > (Index) list_length(q->rtable) ||
1892 list_nth_node(RangeTblEntry, q->rtable, v->varno - 1)->rtekind
1895 if (c->constisnull || bound[v->varno] != NULL)
1897 bound[v->varno] = (Node *) c;
1903 foreach(lc, q->rtable) {
1904 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1906 if (r->rtekind != RTE_CTE)
1908 if (bound[rti] == NULL)
1911 Const *c = (Const *) bound[rti];
1914 getTypeOutputInfo(c->consttype, &out_func, &is_varlena);
1915 const_texts = lappend(const_texts,
1916 OidOutputFunctionCall(out_func, c->constvalue));
1920 cand = (ReachConjCandidate *) palloc(
sizeof(ReachConjCandidate));
1921 cand->ctename = pstrdup(cte->ctename);
1922 cand->node_colname = pstrdup(strVal(linitial(cte->ctecolnames)));
1923 cand->const_texts = const_texts;
1924 return list_make1(cand);
1934static void plant_reach_conjunctions(List *candidates, List *lowered) {
1936 foreach(lc, candidates) {
1937 ReachConjCandidate *cand = (ReachConjCandidate *) lfirst(lc);
1940 StringInfoData call;
1943 foreach(ll, lowered) {
1945 if (strcmp(e->
name, cand->ctename) == 0) {
1950 if (entry == NULL || !entry->reach_routed)
1953 initStringInfo(&call);
1954 appendStringInfo(&call,
1955 "SELECT provsql.plant_reach_cover(%s, %s, ",
1956 quote_literal_cstr(cand->ctename),
1957 quote_literal_cstr(cand->node_colname));
1958 if (OidIsValid(entry->edge_relid))
1959 appendStringInfo(&call,
"%u::pg_catalog.regclass", entry->edge_relid);
1961 appendStringInfoString(&call,
"NULL::pg_catalog.regclass");
1962 appendStringInfo(&call,
", %s, %s, %s, %s, ",
1963 quote_literal_cstr(entry->src_name),
1964 quote_literal_cstr(entry->dst_name),
1966 ? quote_literal_cstr(entry->source_text) :
"NULL",
1967 entry->directed ?
"true" :
"false");
1968 appendStringInfoString(&call,
"ARRAY[");
1969 foreach(ll, cand->const_texts) {
1970 appendStringInfo(&call,
"%s%s", first ?
"" :
", ",
1971 quote_literal_cstr((
const char *) lfirst(ll)));
1974 appendStringInfo(&call,
"]::text[], %s, ",
1976 ? quote_literal_cstr(entry->edge_quals) :
"NULL");
1977 if (OidIsValid(entry->source_relid))
1978 appendStringInfo(&call,
"%u::pg_catalog.regclass, %s, ",
1979 entry->source_relid,
1980 quote_literal_cstr(entry->source_attname));
1982 appendStringInfoString(&call,
"NULL, NULL, ");
1983 appendStringInfo(&call,
"%s)",
1985 ? quote_literal_cstr(entry->edge_sql) :
"NULL");
1987 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
1988 provsql_error(
"Reachability conjunction planting: SPI_connect failed (%d)", rc);
1989 rc = SPI_execute(call.data,
false, 0);
1992 provsql_error(
"Reachability conjunction planting failed (%d)", rc);
2002 List *lowered = NIL;
2005#if PG_VERSION_NUM >= 150000
2006 List *reach_aggs = NIL;
2007 List *reach_conjs = NIL;
2009 if (q->cteList == NIL)
2026 bool passthrough_recursion =
false;
2027 bool any_tracked =
false;
2028 foreach (lc, q->cteList) {
2029 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
2032 else if (cte->cterecursive)
2033 passthrough_recursion =
true;
2035 if (passthrough_recursion && !any_tracked)
2053 int n = list_length(q->cteList);
2054 bool *must_inline = (
bool *)palloc(n *
sizeof(
bool));
2057 foreach (lc, q->cteList) {
2058 CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc);
2059 must_inline[i++] = cte->cterecursive ||
2065 foreach (lc, q->cteList) {
2066 CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc);
2067 if (!must_inline[i]) {
2070 foreach (lc2, q->cteList) {
2071 CommonTableExpr *other = (CommonTableExpr *)lfirst(lc2);
2072 if (must_inline[j] &&
2074 must_inline[i] =
true;
2085 foreach (lc, q->cteList) {
2086 CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc);
2087 if (!must_inline[i])
2088 kept = lappend(kept, cte);
2089 else if (!cte->cterecursive && cte->cterefcount > 1 &&
2090 contain_volatile_functions((Node *)cte->ctequery))
2096 "inlined at each of its %d references; its volatile "
2097 "expressions (e.g. random-variable constructors) are "
2098 "re-evaluated per reference and not shared between "
2100 cte->ctename, cte->cterefcount);
2106#if PG_VERSION_NUM >= 150000
2111 reach_aggs = detect_reach_aggregations(q);
2112 reach_conjs = detect_reach_conjunctions(q);
2115#if PG_VERSION_NUM >= 150000
2116 plant_reach_aggregations(reach_aggs, lowered);
2117 plant_reach_conjunctions(reach_conjs, lowered);
2157 bool in_boolean_rewrite,
bool top_level,
2159 List *prov_atts = NIL;
2161 for(Index rteid = 1; rteid <= q->rtable->length; ++rteid) {
2162 RangeTblEntry *r = list_nth_node(RangeTblEntry, q->rtable, rteid-1);
2164 if (r->rtekind == RTE_RELATION) {
2166 AttrNumber attid = 1;
2175 if (r->relkind == RELKIND_VIEW)
2178 foreach (lc, r->eref->colnames) {
2179 const char *v = strVal(lfirst(lc));
2190 }
else if (r->rtekind == RTE_SUBQUERY) {
2198 bool arm_top_level = top_level && q->setOperations != NULL
2199 && IsA(q->setOperations, SetOperationStmt)
2200 && ((SetOperationStmt *) q->setOperations)->op == SETOP_UNION;
2201 bool *inner_removed = NULL;
2202 int old_targetlist_length =
2203 r->subquery->targetList ? r->subquery->targetList->length : 0;
2204 Query *new_subquery =
2205 process_query(constants, r->subquery, &inner_removed,
false, arm_top_level,
2207 (inv_ctx && rteid - 1 < (Index) inv_ctx->
natoms)
2208 ? inv_ctx->
sub[rteid - 1] : NULL);
2209 if (new_subquery != NULL) {
2211 int *offset = (
int *)palloc(old_targetlist_length *
sizeof(
int));
2212 unsigned varattnoprovsql;
2213 ListCell *cell, *prev;
2215 r->subquery = new_subquery;
2217 if (inner_removed != NULL) {
2218 for (cell = list_head(r->eref->colnames), prev = NULL;
2220 if (inner_removed[i]) {
2224 cell =
my_lnext(r->eref->colnames, prev);
2226 cell = list_head(r->eref->colnames);
2229 cell =
my_lnext(r->eref->colnames, cell);
2233 for (i = 0; i < old_targetlist_length; ++i) {
2235 (i == 0 ? 0 : offset[i - 1]) - (inner_removed[i] ? 1 : 0);
2241 varattnoprovsql = 0;
2242 for (cell = list_head(new_subquery->targetList); cell != NULL;
2243 cell =
my_lnext(new_subquery->targetList, cell)) {
2244 TargetEntry *te = (TargetEntry *)lfirst(cell);
2259 if (cell == NULL && q->setOperations != NULL &&
2260 IsA(q->setOperations, SetOperationStmt) &&
2261 ((SetOperationStmt *)q->setOperations)->op == SETOP_UNION) {
2262 FuncExpr *one_expr = makeNode(FuncExpr);
2263 TargetEntry *one_te;
2266 one_expr->args = NIL;
2267 one_expr->location = -1;
2268 one_te = makeTargetEntry((Expr *)one_expr,
2269 list_length(new_subquery->targetList) + 1,
2271 new_subquery->targetList = lappend(new_subquery->targetList, one_te);
2272 varattnoprovsql = list_length(new_subquery->targetList);
2273 cell = list_tail(new_subquery->targetList);
2277 r->eref->colnames =
list_insert_nth(r->eref->colnames, varattnoprovsql-1,
2281 constants, q, r, rteid, varattnoprovsql));
2284 r->subquery->targetList);
2286 }
else if (r->rtekind == RTE_JOIN) {
2287 if (r->jointype == JOIN_INNER || r->jointype == JOIN_LEFT ||
2288 r->jointype == JOIN_FULL || r->jointype == JOIN_RIGHT) {
2297 }
else if (r->rtekind == RTE_FUNCTION) {
2299 AttrNumber attid = 1;
2301 foreach (lc, r->functions) {
2302 RangeTblFunction *func = (RangeTblFunction *)lfirst(lc);
2304 if (func->funccolcount == 1) {
2305 FuncExpr *expr = (FuncExpr *)func->funcexpr;
2309 constants, q, r, rteid, attid));
2313 "attributes not supported");
2316 attid += func->funccolcount;
2318 }
else if (r->rtekind == RTE_VALUES) {
2320#if PG_VERSION_NUM >= 120000
2321 }
else if (r->rtekind == RTE_RESULT) {
2325#if PG_VERSION_NUM >= 180000
2326 }
else if (r->rtekind == RTE_GROUP) {
2330 }
else if (r->rtekind == RTE_CTE) {
2371 Bitmapset *ressortgrouprefs = NULL;
2372 ListCell *cell, *prev;
2373 *removed = (
bool *)palloc(q->targetList->length *
sizeof(
bool));
2375 for (cell = list_head(q->targetList), prev = NULL; cell != NULL;) {
2376 TargetEntry *rt = (TargetEntry *)lfirst(cell);
2377 (*removed)[i] =
false;
2379 if (rt->expr->type == T_Var) {
2380 Var *v = (Var *)rt->expr;
2383 const char *colname;
2386 colname = rt->resname;
2390 RangeTblEntry *r = (RangeTblEntry *)list_nth(q->rtable, v->varno - 1);
2391 colname = strVal(list_nth(r->eref->colnames, v->varattno - 1));
2397 (*removed)[i] =
true;
2400 if (rt->ressortgroupref > 0)
2402 bms_add_member(ressortgrouprefs, rt->ressortgroupref);
2407 if ((*removed)[i]) {
2409 cell =
my_lnext(q->targetList, prev);
2411 cell = list_head(q->targetList);
2414 rt->resno -= nbRemoved;
2416 cell =
my_lnext(q->targetList, cell);
2422 return ressortgrouprefs;
2443 List *evidence = NIL;
2445 ListCell *cell, *prev;
2450 for (cell = list_head(q->targetList), prev = NULL; cell != NULL;) {
2451 TargetEntry *rt = (TargetEntry *)lfirst(cell);
2452 bool is_given =
false;
2458 if (!rt->resjunk && IsA(rt->expr, FuncExpr) &&
2460 args = ((FuncExpr *)rt->expr)->args;
2461 else if (!rt->resjunk && IsA(rt->expr, OpExpr) &&
2463 args = ((OpExpr *)rt->expr)->args;
2466 if (list_length(args) != 1)
2467 provsql_error(
"provsql.given expects exactly one argument");
2469 evidence = lappend(evidence, linitial(args));
2475 cell = prev ?
my_lnext(q->targetList, prev) : list_head(q->targetList);
2477 rt->resno -= nbRemoved;
2479 cell =
my_lnext(q->targetList, cell);
2531 OpExpr *fromOpExpr, Expr *toExpr,
2541 if (
my_lnext(fromOpExpr->args, list_head(fromOpExpr->args))) {
2543 if (IsA(linitial(fromOpExpr->args), Var)) {
2544 v1 = linitial(fromOpExpr->args);
2545 }
else if (IsA(linitial(fromOpExpr->args), RelabelType)) {
2547 RelabelType *rt1 = linitial(fromOpExpr->args);
2548 if (IsA(rt1->arg, Var)) {
2549 v1 = (Var *)rt1->arg;
2554 if (!columns[v1->varno - 1])
2556 first_arg = Int16GetDatum(columns[v1->varno - 1][v1->varattno - 1]);
2558 if (IsA(lsecond(fromOpExpr->args), Var)) {
2559 v2 = lsecond(fromOpExpr->args);
2560 }
else if (IsA(lsecond(fromOpExpr->args), RelabelType)) {
2562 RelabelType *rt2 = lsecond(fromOpExpr->args);
2563 if (IsA(rt2->arg, Var)) {
2564 v2 = (Var *)rt2->arg;
2569 if (!columns[v2->varno - 1])
2571 second_arg = Int16GetDatum(columns[v2->varno - 1][v2->varattno - 1]);
2573 fc = makeNode(FuncExpr);
2575 fc->funcvariadic =
false;
2579 c1 = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int16),
2580 first_arg,
false,
true);
2582 c2 = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int16),
2583 second_arg,
false,
true);
2585 fc->args = list_make3(toExpr, c1, c2);
2607 Node *quals, Expr *result,
2614 if (IsA(quals, OpExpr)) {
2615 oe = (OpExpr *)quals;
2618 else if (IsA(quals, BoolExpr)) {
2619 BoolExpr *be = (BoolExpr *)quals;
2621 if (be->boolop == OR_EXPR || be->boolop == NOT_EXPR) {
2622 provsql_error(
"Boolean operators OR and NOT in a join...on "
2623 "clause are not supported");
2626 foreach (lc2, be->args) {
2627 if (IsA(lfirst(lc2), OpExpr)) {
2628 oe = (OpExpr *)lfirst(lc2);
2653 if (
my_lnext(prov_atts, list_head(prov_atts)) == NULL)
2654 return (Expr *)linitial(prov_atts);
2656 combine = makeNode(FuncExpr);
2658 ArrayExpr *array = makeNode(ArrayExpr);
2661 combine->funcvariadic =
true;
2665 array->elements = prov_atts;
2666 array->location = -1;
2668 combine->args = list_make1(array);
2671 combine->args = prov_atts;
2674 combine->location = -1;
2675 return (Expr *)combine;
2687 Oid aggfnoid, Expr *arg) {
2688 TargetEntry *te = makeNode(TargetEntry);
2689 Aggref *agg = makeNode(Aggref);
2694 agg->aggfnoid = aggfnoid;
2697 agg->aggkind = AGGKIND_NORMAL;
2698 agg->aggtranstype = InvalidOid;
2699 agg->args = list_make1(te);
2701#if PG_VERSION_NUM >= 140000
2702 agg->aggno = agg->aggtransno = -1;
2736 Aggref *agg_ref, List *prov_atts,
2739 Expr *rv_arg = ((TargetEntry *)linitial(agg_ref->args))->expr;
2740 Oid aggfnoid = agg_ref->aggfnoid;
2744 double identity = 0.0;
2757 FuncExpr *num_wrap = makeNode(FuncExpr);
2758 FuncExpr *ind_wrap = makeNode(FuncExpr);
2759 FuncExpr *div = makeNode(FuncExpr);
2763 num_wrap->args = list_make2(prov_expr, rv_arg);
2764 num_wrap->location = -1;
2773 ind_wrap->args = list_make2(copyObject(prov_expr), copyObject(rv_arg));
2776 ind_wrap->args = list_make1(copyObject(prov_expr));
2779 ind_wrap->location = -1;
2786 div->args = list_make2(
2802 Oid impl_oid = InvalidOid;
2803 bool is_percentile =
false;
2804 bool is_stat_agg =
true;
2824 is_percentile =
true;
2826 is_stat_agg =
false;
2828 if (OidIsValid(impl_oid) &&
2830 FuncExpr *ind_wrap = makeNode(FuncExpr);
2831 Aggref *impl_agg = makeNode(Aggref);
2832 List *arg_exprs = NIL;
2833 List *arg_types = NIL;
2839 ind_wrap->args = list_make1(prov_expr);
2840 ind_wrap->location = -1;
2842 if (is_percentile) {
2848 Expr *fraction = (Expr *)linitial(agg_ref->aggdirectargs);
2849 arg_exprs = list_make1(copyObject(fraction));
2850 arg_types = list_make1_oid(FLOAT8OID);
2852 arg_exprs = lappend(arg_exprs, ind_wrap);
2854 foreach (lc, agg_ref->args) {
2855 TargetEntry *arg_te = (TargetEntry *)lfirst(lc);
2856 arg_exprs = lappend(arg_exprs, arg_te->expr);
2857 arg_types = lappend_oid(arg_types,
2861 impl_agg->aggfnoid = impl_oid;
2863 impl_agg->aggargtypes = arg_types;
2864 impl_agg->aggkind = AGGKIND_NORMAL;
2865 impl_agg->aggtranstype = InvalidOid;
2866 impl_agg->args = NIL;
2867 foreach (lc, arg_exprs) {
2868 TargetEntry *arg_te = makeNode(TargetEntry);
2869 arg_te->resno = resno++;
2870 arg_te->expr = (Expr *)lfirst(lc);
2871 impl_agg->args = lappend(impl_agg->args, arg_te);
2873 impl_agg->location = agg_ref->location;
2874#if PG_VERSION_NUM >= 140000
2875 impl_agg->aggno = impl_agg->aggtransno = -1;
2877 return (Expr *)impl_agg;
2880 provsql_error(
"statistic aggregate over random_variable requires the "
2881 "rv_*_impl aggregates (schema too old; run ALTER "
2882 "EXTENSION provsql UPDATE)");
2893 identity = -get_float8_infinity();
2897 identity = get_float8_infinity();
2901 wrap = makeNode(FuncExpr);
2903 Const *id_const = makeConst(FLOAT8OID, -1, InvalidOid,
sizeof(float8),
2904 Float8GetDatum(identity),
false,
2907 wrap->args = list_make3(prov_expr, rv_arg, id_const);
2912 wrap->args = list_make2(prov_expr, rv_arg);
2915 wrap->location = -1;
2918 te = makeNode(TargetEntry);
2920 te->expr = (Expr *)wrap;
2922 new_agg = makeNode(Aggref);
2923 new_agg->aggfnoid = aggfnoid;
2926 new_agg->aggkind = AGGKIND_NORMAL;
2927 new_agg->aggtranstype = InvalidOid;
2928 new_agg->args = list_make1(te);
2929 new_agg->location = agg_ref->location;
2930#if PG_VERSION_NUM >= 140000
2931 new_agg->aggno = new_agg->aggtransno = -1;
2934 return (Expr *)new_agg;
2960 Aggref *agg_ref, List *prov_atts,
2963 FuncExpr *expr, *expr_s;
2964 Aggref *agg = makeNode(Aggref);
2965 FuncExpr *plus = makeNode(FuncExpr);
2966 TargetEntry *te_inner = makeNode(TargetEntry);
2967 Const *fn = makeNode(Const);
2968 Const *typ = makeNode(Const);
2971 result = linitial(prov_atts);
2973 Oid aggregation_function = agg_ref->aggfnoid;
2987 if (
my_lnext(prov_atts, list_head(prov_atts)) == NULL)
2988 expr = linitial(prov_atts);
2990 expr = makeNode(FuncExpr);
2992 ArrayExpr *array = makeNode(ArrayExpr);
2995 expr->funcvariadic =
true;
2999 array->elements = prov_atts;
3000 array->location = -1;
3002 expr->args = list_make1(array);
3005 expr->args = prov_atts;
3008 expr->location = -1;
3012 expr_s = makeNode(FuncExpr);
3017 if (aggregation_function ==
F_COUNT_)
3026 Const *one = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
3027 sizeof(int32), Int32GetDatum(1),
false,
true);
3028 expr_s->args = list_make2(one, expr);
3039 Expr *arg = ((TargetEntry *)linitial(agg_ref->args))->expr;
3040 CaseExpr *ce = makeNode(CaseExpr);
3041 CaseWhen *cw = makeNode(CaseWhen);
3042 NullTest *nt = makeNode(NullTest);
3044 nt->arg = (Expr *)arg;
3045 nt->nulltesttype = IS_NOT_NULL;
3046 nt->argisrow =
false;
3049 cw->expr = (Expr *)nt;
3050 cw->result = (Expr *)makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
3051 sizeof(int32), Int32GetDatum(1),
false,
3056 ce->casecollid = InvalidOid;
3058 ce->args = list_make1(cw);
3059 ce->defresult = (Expr *)makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
3060 sizeof(int32), Int32GetDatum(0),
false,
3064 expr_s->args = list_make2(ce, expr);
3076 list_make2(((TargetEntry *)linitial(agg_ref->args))->expr, expr);
3079 expr_s->location = -1;
3082 te_inner->resno = 1;
3083 te_inner->expr = (Expr *)expr_s;
3086 agg->args = list_make1(te_inner);
3087 agg->aggkind = AGGKIND_NORMAL;
3089#if PG_VERSION_NUM >= 140000
3090 agg->aggno = agg->aggtransno = -1;
3093 agg->aggargtypes = list_make1_oid(constants->
OID_TYPE_UUID);
3103 if (agg_ref->aggorder != NIL) {
3104 AttrNumber sort_resno = 2;
3106 foreach (lc, agg_ref->args) {
3107 TargetEntry *arg_te = (TargetEntry *)lfirst(lc);
3108 TargetEntry *te_sort;
3109 if (arg_te->ressortgroupref == 0)
3111 te_sort = makeTargetEntry((Expr *)copyObject(arg_te->expr),
3112 sort_resno++, NULL,
true);
3113 te_sort->ressortgroupref = arg_te->ressortgroupref;
3114 agg->args = lappend(agg->args, te_sort);
3116 agg->aggorder = (List *)copyObject((Node *)agg_ref->aggorder);
3122 fn = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
3123 Int32GetDatum(aggregation_function),
false,
true);
3130 typ = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
3131 Int32GetDatum(agg_ref->aggtype),
false,
true);
3134 plus->args = list_make5(fn, typ, agg_ref, agg,
3135 makeConst(BOOLOID, -1, InvalidOid,
sizeof(
bool),
3136 BoolGetDatum(is_scalar),
false,
true));
3137 plus->location = -1;
3139 result = (Expr *)plus;
3189 if (IsA(node, Var) &&
3194 if (IsA(node, FuncExpr) &&
3195 ((FuncExpr *)node)->funcid ==
3220 if (n == NULL || !IsA(n, Const) || ((Const *)n)->constisnull)
3223 getTypeOutputInfo(c->consttype, &outfunc, &isvarlena);
3224 s = OidOutputFunctionCall(outfunc, c->constvalue);
3232 ParseState *p = make_parsestate(NULL);
3233 Node *e = (Node *)make_op(p, list_make1(makeString(pstrdup(op))),
3252 Node *a, *b, *agg_side, *thr;
3257 if (list_length(cmp->args) != 2)
3259 a = (Node *)linitial(cmp->args);
3260 b = (Node *)lsecond(cmp->args);
3268 agg_side = a; thr = b;
3270 agg_side = b; thr = a;
3271 opno = get_commutator(opno);
3272 if (!OidIsValid(opno))
3285 if (peeled == NULL || !IsA(peeled, OpExpr)) {
3289 inner = (OpExpr *)peeled;
3290 iname = get_opname(inner->opno);
3293 nin = list_length(inner->args);
3295 if (nin == 1 && strcmp(iname,
"-") == 0) {
3298 agg_side = (Node *)linitial(inner->args);
3299 }
else if (nin == 2) {
3300 Node *x = (Node *)linitial(inner->args);
3301 Node *y = (Node *)lsecond(inner->args);
3309 if (x_agg) { agg_side = x; c = y; agg_left =
true; }
3310 else { agg_side = y; c = x; agg_left =
false; }
3312 if (strcmp(iname,
"+") == 0) {
3314 }
else if (strcmp(iname,
"-") == 0) {
3321 }
else if (strcmp(iname,
"/") == 0) {
3327 Oid divtype = exprType(peeled);
3329 if (divtype == INT2OID || divtype == INT4OID || divtype == INT8OID)
3336 }
else if (strcmp(iname,
"*") == 0) {
3346 thr_num = coerce_to_target_type(NULL, thr, exprType(thr),
3347 NUMERICOID, -1, COERCION_EXPLICIT,
3348 COERCE_EXPLICIT_CAST, -1);
3349 if (thr_num == NULL)
3362 opno = get_commutator(opno);
3363 if (!OidIsValid(opno))
3368 res = makeNode(OpExpr);
3370 res->opresulttype = BOOLOID;
3371 res->opretset =
false;
3372 res->opcollid = InvalidOid;
3373 res->inputcollid = cmp->inputcollid;
3374 res->location = cmp->location;
3375 res->args = list_make2(agg_side, thr);
3413 opno = opExpr->opno;
3415 for (
unsigned i = 0; i < 2; ++i) {
3416 Node *node = (Node *)lfirst(list_nth_cell(opExpr->args, i));
3417 Node *agg_node = NULL;
3419 if (IsA(node, FuncExpr)) {
3420 FuncExpr *fe = (FuncExpr *)node;
3421 if (fe->funcformat == COERCE_IMPLICIT_CAST ||
3422 fe->funcformat == COERCE_EXPLICIT_CAST) {
3423 if (fe->args->length == 1)
3424 node = lfirst(list_head(fe->args));
3440 if (swapped != NULL &&
3445 if (agg_node != NULL) {
3447 FuncExpr *castToUUID = makeNode(FuncExpr);
3451 castToUUID->args = list_make1(agg_node);
3452 castToUUID->location = -1;
3454 arguments[i] = (Node *)castToUUID;
3463 FuncExpr *oneExpr = makeNode(FuncExpr);
3464 FuncExpr *semimodExpr = makeNode(FuncExpr);
3469 oneExpr->args = NIL;
3470 oneExpr->location = -1;
3475 semimodExpr->args = list_make2((Expr *)node, (Expr *)oneExpr);
3476 semimodExpr->location = -1;
3478 arguments[i] = (Node *)semimodExpr;
3485 opno = get_negator(opno);
3490 oid = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
3491 Int32GetDatum(opno),
false,
true);
3493 cmpExpr = makeNode(FuncExpr);
3496 cmpExpr->args = list_make3(arguments[0], oid, arguments[1]);
3497 cmpExpr->location = opExpr->location;
3516 Aggref *base_arr, Node *V, Node *K,
3517 NullTestType filter) {
3518 Aggref *arr = (Aggref *)copyObject(base_arr);
3519 TargetEntry *te = (TargetEntry *)linitial(arr->args);
3520 NullTest *flt = makeNode(NullTest);
3521 ArrayExpr *empty = makeNode(ArrayExpr);
3522 CoalesceExpr *coal = makeNode(CoalesceExpr);
3523 FuncExpr *plus = makeNode(FuncExpr);
3525 te->expr = (Expr *)copyObject(K);
3529 flt->arg = (Expr *)copyObject(V);
3530 flt->nulltesttype = filter;
3531 flt->argisrow =
false;
3533 arr->aggfilter = (Expr *)flt;
3536 empty->array_collid = InvalidOid;
3538 empty->elements = NIL;
3539 empty->multidims =
false;
3540 empty->location = -1;
3543 coal->coalescecollid = InvalidOid;
3544 coal->args = list_make2(arr, empty);
3545 coal->location = -1;
3549 plus->funcvariadic =
true;
3550 plus->args = list_make1(coal);
3551 plus->location = -1;
3585 Node *arg = (Node *)nt->arg;
3586 FuncExpr *pa, *plusKn;
3593 if (IsA(arg, FuncExpr)) {
3594 FuncExpr *fe = (FuncExpr *)arg;
3595 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
3596 fe->funcformat == COERCE_EXPLICIT_CAST) &&
3597 list_length(fe->args) == 1)
3598 arg = (Node *)linitial(fe->args);
3600 if (!IsA(arg, FuncExpr) ||
3602 provsql_error(
"HAVING IS [NOT] NULL is only supported directly on an "
3603 "aggregate of a provenance-tracked relation");
3604 pa = (FuncExpr *)arg;
3612 is_scalar = DatumGetBool(((Const *)list_nth(pa->args, 4))->constvalue);
3614 Aggref *arr = (Aggref *)list_nth(pa->args, 3);
3617 if (!IsA(arr, Aggref) || list_length(arr->args) != 1)
3618 provsql_error(
"unexpected aggregate shape in HAVING IS [NOT] NULL");
3619 te = (TargetEntry *)linitial(arr->args);
3620 if (!IsA(te->expr, FuncExpr) ||
3622 provsql_error(
"unexpected aggregate shape in HAVING IS [NOT] NULL");
3623 sm = (FuncExpr *)te->expr;
3624 V = (Node *)list_nth(sm->args, 0);
3625 K = (Node *)list_nth(sm->args, 1);
3629 ntt = nt->nulltesttype;
3631 ntt = (ntt == IS_NULL) ? IS_NOT_NULL : IS_NULL;
3636 if (ntt == IS_NOT_NULL) {
3638 FuncExpr *delta = makeNode(FuncExpr);
3641 delta->args = list_make1(plusKn);
3642 delta->location = -1;
3648 FuncExpr *one = makeNode(FuncExpr);
3649 FuncExpr *monus = makeNode(FuncExpr);
3656 monus->args = list_make2(one, plusKn);
3657 monus->location = -1;
3667 FuncExpr *deltaKz = makeNode(FuncExpr);
3668 FuncExpr *times = makeNode(FuncExpr);
3669 ArrayExpr *factors = makeNode(ArrayExpr);
3673 deltaKz->args = list_make1(plusKz);
3674 deltaKz->location = -1;
3677 factors->array_collid = InvalidOid;
3679 factors->elements = list_make2(deltaKz, monus);
3680 factors->multidims =
false;
3681 factors->location = -1;
3685 times->funcvariadic =
true;
3686 times->args = list_make1(factors);
3687 times->location = -1;
3704 Expr *expr,
bool negated) {
3705 FuncExpr *ind = makeNode(FuncExpr);
3707 provsql_error(
"a regular comparison in a probabilistic predicate requires "
3708 "provsql.regular_indicator (schema too old)");
3711 ind->funcretset =
false;
3712 ind->funcvariadic =
false;
3713 ind->funcformat = COERCE_EXPLICIT_CALL;
3714 ind->funccollid = InvalidOid;
3715 ind->inputcollid = InvalidOid;
3716 ind->args = list_make1(negated
3717 ? (Expr *) makeBoolExpr(NOT_EXPR, list_make1(expr), -1)
3737 if(be->boolop == NOT_EXPR) {
3738 Expr *expr = (Expr *) lfirst(list_head(be->args));
3744 ArrayExpr *array = makeNode(ArrayExpr);
3748 array->location = -1;
3750 result = makeNode(FuncExpr);
3752 result->funcvariadic =
true;
3753 result->location = be->location;
3754 result->args = list_make1(array);
3756 if ((be->boolop == AND_EXPR && !negated) || (be->boolop == OR_EXPR && negated))
3758 else if ((be->boolop == AND_EXPR && negated) || (be->boolop == OR_EXPR && !negated))
3763 foreach (lc, be->args) {
3764 Expr *expr = (Expr *)lfirst(lc);
3766 l = lappend(l, arg);
3769 array->elements = l;
3794 if (IsA(expr, BoolExpr))
3796 else if (IsA(expr, OpExpr))
3798 else if (IsA(expr, NullTest))
3801 provsql_error(
"Unknown structure within Boolean expression");
3834 for (
int i = 0; i < 6; ++i) {
3855 RelabelType *rt = makeNode(RelabelType);
3856 rt->arg = (Expr *) operand;
3858 rt->resulttypmod = -1;
3859 rt->resultcollid = InvalidOid;
3860 rt->relabelformat = COERCE_IMPLICIT_CAST;
3881 if (node && IsA(node, RelabelType))
3882 node = (Node *)((RelabelType *)node)->arg;
3883 return node && IsA(node, Const) && ((Const *)node)->constisnull;
3907 Oid opno = opExpr->opno;
3908 Node *left = (Node *)linitial(opExpr->args);
3909 Node *right = (Node *)lsecond(opExpr->args);
3917 FuncExpr *zero = makeNode(FuncExpr);
3921 zero->location = opExpr->location;
3926 opno = get_negator(opno);
3928 provsql_error(
"Missing negator for random_variable comparison");
3931 oid_const = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
3932 sizeof(int32), Int32GetDatum(opno),
false,
true);
3934 cmpExpr = makeNode(FuncExpr);
3937 cmpExpr->args = list_make3(
3941 cmpExpr->location = opExpr->location;
3963 if (be->boolop == NOT_EXPR) {
3964 Expr *child = (Expr *)linitial(be->args);
3968 array = makeNode(ArrayExpr);
3971 array->location = -1;
3973 result = makeNode(FuncExpr);
3975 result->funcvariadic =
true;
3976 result->location = be->location;
3977 result->args = list_make1(array);
3979 if ((be->boolop == AND_EXPR && !negated) ||
3980 (be->boolop == OR_EXPR && negated))
3982 else if ((be->boolop == AND_EXPR && negated) ||
3983 (be->boolop == OR_EXPR && !negated))
3986 provsql_error(
"Unknown Boolean operator in random_variable WHERE clause");
3988 foreach (lc, be->args) {
3990 constants, negated);
3991 l = lappend(l, arg);
3993 array->elements = l;
4013 if (IsA(expr, BoolExpr))
4015 if (IsA(expr, OpExpr)) {
4016 OpExpr *opExpr = (OpExpr *)expr;
4020 provsql_error(
"Unsupported sub-expression in random_variable WHERE clause "
4021 "(only Boolean combinations of RV comparisons, optionally "
4022 "mixed with ordinary comparisons, are accepted)");
4038 if (IsA(node, OpExpr)) {
4039 OpExpr *op = (OpExpr *)node;
4072 FuncExpr *ind = makeNode(FuncExpr);
4074 provsql_error(
"conditioning on an ordinary (regular) comparison requires "
4075 "provsql.regular_indicator (schema too old)");
4078 ind->funcretset =
false;
4079 ind->funcvariadic =
false;
4080 ind->funcformat = COERCE_EXPLICIT_CALL;
4081 ind->funccollid = InvalidOid;
4082 ind->inputcollid = InvalidOid;
4083 ind->args = list_make1(negated
4084 ? (Expr *) makeBoolExpr(NOT_EXPR, list_make1(expr), -1)
4090 if (IsA(expr, BoolExpr)) {
4091 BoolExpr *be = (BoolExpr *)expr;
4097 if (be->boolop == NOT_EXPR)
4099 constants, !negated);
4101 array = makeNode(ArrayExpr);
4104 array->location = -1;
4106 result = makeNode(FuncExpr);
4108 result->funcvariadic =
true;
4109 result->location = be->location;
4110 result->args = list_make1(array);
4111 if ((be->boolop == AND_EXPR && !negated) ||
4112 (be->boolop == OR_EXPR && negated))
4117 foreach (lc, be->args)
4119 constants, negated));
4120 array->elements = l;
4124 if (IsA(expr, OpExpr)) {
4125 OpExpr *op = (OpExpr *)expr;
4132 provsql_error(
"The right operand of the conditioning operator | must be a "
4133 "Boolean combination of random_variable or aggregate "
4134 "comparisons (e.g. \"X | (X > 3)\")");
4147 Oid *cond_fn, Oid *result_type,
4165 return OidIsValid(*cond_fn);
4185 if (IsA(node, OpExpr)) {
4186 OpExpr *op = (OpExpr *)node;
4187 Oid cond_fn, result_type;
4198 FuncExpr *target_gate, *evidence_gate, *cond;
4200 provsql_error(
"(predicate) | (predicate) needs at least one "
4201 "random_variable / aggregate comparison; conditioning "
4202 "two purely regular Booleans is not an event -- use a "
4203 "WHERE clause instead");
4204 if (!OidIsValid(constants->OID_FUNCTION_COND))
4205 provsql_error(
"conditioning two comparison events with | requires "
4206 "provsql.cond (schema too old)");
4211 cond = makeNode(FuncExpr);
4212 cond->funcid = constants->OID_FUNCTION_COND;
4213 cond->funcresulttype = constants->OID_TYPE_UUID;
4214 cond->funcretset =
false;
4215 cond->funcvariadic =
false;
4216 cond->funcformat = COERCE_EXPLICIT_CALL;
4217 cond->funccollid = InvalidOid;
4218 cond->inputcollid = InvalidOid;
4219 cond->args = list_make2(target_gate, evidence_gate);
4220 cond->location = op->location;
4221 return (Node *) cond;
4225 FuncExpr *gate, *cond;
4226 Expr *pred = (Expr *)llast(op->args);
4233 provsql_error(
"the conditioning operator | needs a predicate with at "
4234 "least one random_variable / aggregate comparison; a "
4235 "purely regular condition is an ordinary filter -- use a "
4236 "WHERE clause instead");
4238 cond = makeNode(FuncExpr);
4239 cond->funcid = cond_fn;
4240 cond->funcresulttype = result_type;
4241 cond->funcretset =
false;
4242 cond->funcvariadic =
false;
4243 cond->funcformat = COERCE_EXPLICIT_CALL;
4244 cond->funccollid = InvalidOid;
4245 cond->inputcollid = InvalidOid;
4247 cond->args = list_make1(gate);
4249 Expr *target = (Expr *)expression_tree_mutator(
4251 cond->args = list_make2(target, gate);
4253 cond->location = op->location;
4254 return (Node *) cond;
4263 if (IsA(node, FuncExpr) &&
4266 FuncExpr *fe = (FuncExpr *)node;
4267 Expr *pred = (Expr *)linitial(fe->args);
4268 FuncExpr *gate, *given;
4270 provsql_error(
"given(predicate) needs a predicate with at least one "
4271 "random_variable / aggregate comparison; a purely regular "
4272 "condition is an ordinary filter -- use a WHERE clause");
4274 given = makeNode(FuncExpr);
4275 given->funcid = constants->OID_FUNCTION_GIVEN;
4276 given->funcresulttype = constants->OID_TYPE_UUID;
4277 given->funcretset =
false;
4278 given->funcvariadic =
false;
4279 given->funcformat = COERCE_EXPLICIT_CALL;
4280 given->funccollid = InvalidOid;
4281 given->inputcollid = InvalidOid;
4282 given->args = list_make1(gate);
4283 given->location = fe->location;
4284 return (Node *) given;
4299 q->targetList = (List *)expression_tree_mutator(
4301 if (q->jointree && q->jointree->quals)
4302 q->jointree->quals = expression_tree_mutator(
4305 q->havingQual = expression_tree_mutator(
4322 if (IsA(node, OpExpr)) {
4323 OpExpr *opExpr = (OpExpr *)node;
4327 if (IsA(node, BoolExpr)) {
4328 BoolExpr *be = (BoolExpr *)node;
4330 foreach (lc, be->args) {
4364 if (IsA(expr, OpExpr))
4365 return rv_cmp_index(constants, ((OpExpr *)expr)->opfuncid) >= 0;
4366 if (IsA(expr, BoolExpr)) {
4367 BoolExpr *be = (BoolExpr *)expr;
4369 foreach (lc, be->args) {
4397 foreach (lc, ce->args) {
4398 CaseWhen *cw = (CaseWhen *)lfirst(lc);
4421 List *elements = NIL;
4426 foreach (lc, ce->args) {
4427 CaseWhen *cw = (CaseWhen *)lfirst(lc);
4431 elements = lappend(elements, guard);
4432 elements = lappend(elements, value);
4435 elements = lappend(elements,
4438 array = makeNode(ArrayExpr);
4441 array->elements = elements;
4442 array->location = -1;
4444 call = makeNode(FuncExpr);
4447 call->funcretset =
false;
4448 call->funcvariadic =
false;
4449 call->funcformat = COERCE_EXPLICIT_CALL;
4450 call->funccollid = InvalidOid;
4451 call->inputcollid = InvalidOid;
4452 call->args = list_make1(array);
4453 call->location = ce->location;
4454 return (Node *) call;
4463 if (n != NULL && IsA(n, FuncExpr)) {
4464 FuncExpr *fe = (FuncExpr *)n;
4465 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
4466 fe->funcformat == COERCE_EXPLICIT_CAST) &&
4467 list_length(fe->args) == 1)
4468 n = (Node *)linitial(fe->args);
4483 FuncExpr *castToUUID;
4485 if (node != NULL && IsA(node, FuncExpr)) {
4486 FuncExpr *fe = (FuncExpr *)node;
4487 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
4488 fe->funcformat == COERCE_EXPLICIT_CAST) &&
4489 list_length(fe->args) == 1)
4490 node = (Node *)linitial(fe->args);
4496 castToUUID = makeNode(FuncExpr);
4499 castToUUID->funcretset =
false;
4500 castToUUID->funcvariadic =
false;
4501 castToUUID->funcformat = COERCE_EXPLICIT_CALL;
4502 castToUUID->funccollid = InvalidOid;
4503 castToUUID->inputcollid = InvalidOid;
4504 castToUUID->args = list_make1(node);
4505 castToUUID->location = -1;
4506 return (Node *)castToUUID;
4514 FuncExpr *valueGate;
4515 Node *numarg = node;
4516 if (exprType(node) != NUMERICOID) {
4517 numarg = coerce_to_target_type(NULL, node, exprType(node), NUMERICOID, -1,
4518 COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST,
4523 valueGate = makeNode(FuncExpr);
4526 valueGate->funcretset =
false;
4527 valueGate->funcvariadic =
false;
4528 valueGate->funcformat = COERCE_EXPLICIT_CALL;
4529 valueGate->funccollid = InvalidOid;
4530 valueGate->inputcollid = InvalidOid;
4531 valueGate->args = list_make1(numarg);
4532 valueGate->location = -1;
4533 return (Node *)valueGate;
4549 foreach (lc, ce->args) {
4550 CaseWhen *cw = (CaseWhen *)lfirst(lc);
4566 List *elements = NIL;
4572 foreach (lc, ce->args) {
4573 CaseWhen *cw = (CaseWhen *)lfirst(lc);
4581 elements = lappend(elements, guard);
4582 elements = lappend(elements, value);
4587 elements = lappend(elements, value);
4589 array = makeNode(ArrayExpr);
4592 array->elements = elements;
4593 array->location = -1;
4595 call = makeNode(FuncExpr);
4598 call->funcretset =
false;
4599 call->funcvariadic =
false;
4600 call->funcformat = COERCE_EXPLICIT_CALL;
4601 call->funccollid = InvalidOid;
4602 call->inputcollid = InvalidOid;
4603 call->args = list_make1(array);
4604 call->location = ce->location;
4605 return (Node *)call;
4619 CaseExpr *ce = (CaseExpr *)expression_tree_mutator(
4622 return lowered != NULL ? lowered : (Node *)ce;
4636 foreach (lc, q->targetList) {
4637 TargetEntry *te = (TargetEntry *)lfirst(lc);
4661 if (IsA(node, OpExpr))
4662 return rv_cmp_index(constants, ((OpExpr *)node)->opfuncid) >= 0;
4663 if (IsA(node, BoolExpr))
4693 if (IsA(node, MinMaxExpr)) {
4694 MinMaxExpr *mm = (MinMaxExpr *)node;
4699 FuncExpr *call = makeNode(FuncExpr);
4700 ArrayExpr *arr = makeNode(ArrayExpr);
4701 mm = (MinMaxExpr *)expression_tree_mutator(
4705 arr->multidims =
false;
4706 arr->elements = mm->args;
4708 call->funcid = (mm->op == IS_GREATEST)
4712 call->funcretset =
false;
4713 call->funcvariadic =
true;
4714 call->funcformat = COERCE_EXPLICIT_CALL;
4715 call->funccollid = InvalidOid;
4716 call->inputcollid = mm->inputcollid;
4717 call->args = list_make1(arr);
4718 call->location = mm->location;
4719 return (Node *) call;
4725 if (IsA(node, CaseExpr)) {
4726 CaseExpr *ce = (CaseExpr *)node;
4727 if (ce->arg == NULL &&
4731 CaseExpr *mutated = (CaseExpr *)expression_tree_mutator(
4736 if (IsA(node, FuncExpr)) {
4737 FuncExpr *fe = (FuncExpr *)node;
4741 (
void *)constants)) {
4742 Expr *pred = (Expr *)linitial(fe->args);
4744 FuncExpr *call = makeNode(FuncExpr);
4747 Node *method_arg = list_length(fe->args) >= 2
4748 ? (Node *) list_nth(fe->args, 1)
4749 : (Node *) makeNullConst(TEXTOID, -1, InvalidOid);
4750 Node *args_arg = list_length(fe->args) >= 3
4751 ? (Node *) list_nth(fe->args, 2)
4752 : (Node *) makeNullConst(TEXTOID, -1, InvalidOid);
4753 call->funcid = constants->OID_FUNCTION_PROBABILITY_EVALUATE;
4754 call->funcresulttype = constants->OID_TYPE_FLOAT;
4755 call->funcretset =
false;
4756 call->funcvariadic =
false;
4757 call->funcformat = COERCE_EXPLICIT_CALL;
4758 call->funccollid = InvalidOid;
4759 call->inputcollid = InvalidOid;
4760 call->args = list_make3((Expr *)token, method_arg, args_arg);
4761 call->location = fe->location;
4762 return (Node *) call;
4816 q->targetList = (List *)expression_tree_mutator(
4823 foreach (lc, q->targetList) {
4824 TargetEntry *te = (TargetEntry *)lfirst(lc);
4866 q->targetList = (List *)expression_tree_mutator(
4869 foreach (lc, q->rtable) {
4870 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
4871 if (r->rtekind == RTE_VALUES &&
4873 r->values_lists = (List *)expression_tree_mutator(
4891 const char *desc, Expr *fallback)
4894 list_make2(makeString(
"provsql"), makeString(
"ucq_joint_provenance")),
4895 2, NIL,
false,
false,
4904 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
4905 c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
4907 fe = makeNode(FuncExpr);
4908 fe->funcid = fcl->oid;
4910 fe->funcretset =
false;
4911 fe->funcvariadic =
false;
4915 fe->args = list_make2(c, fallback);
4934 const char *desc, Expr *fallback)
4937 list_make2(makeString(
"provsql"), makeString(
"ucq_mobius_provenance")),
4938 2, NIL,
false,
false,
4947 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
4948 c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
4950 fe = makeNode(FuncExpr);
4951 fe->funcid = fcl->oid;
4953 fe->funcretset =
false;
4954 fe->funcvariadic =
false;
4955 fe->args = list_make2(c, fallback);
4973 const char *desc, List *head_var_idx,
4974 List *head_exprs, Expr *fallback)
4977 list_make2(makeString(
"provsql"), makeString(
"ucq_joint_provenance_answer")),
4978 4, NIL,
false,
false,
4981 Const *desc_c, *hv_c;
4985 int n = list_length(head_var_idx), i;
4989 if (fcl == NULL || head_var_idx == NIL)
4992 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
4993 desc_c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
4996 hd = palloc(n *
sizeof(Datum));
4998 foreach (lc, head_var_idx)
4999 hd[i++] = Int32GetDatum(lfirst_int(lc));
5000 arr = construct_array(hd, n, INT4OID,
sizeof(int32),
true,
TYPALIGN_INT);
5001 hv_c = makeConst(INT4ARRAYOID, -1, InvalidOid, -1,
5002 PointerGetDatum(arr),
false,
false);
5008 vals = makeNode(ArrayExpr);
5009 vals->array_typeid = TEXTARRAYOID;
5010 vals->element_typeid = TEXTOID;
5011 vals->multidims =
false;
5012 vals->elements = NIL;
5013 foreach (lc, head_exprs) {
5014 CoerceViaIO *cio = makeNode(CoerceViaIO);
5015 cio->arg = (Expr *) lfirst(lc);
5016 cio->resulttype = TEXTOID;
5017 cio->resultcollid = DEFAULT_COLLATION_OID;
5018 cio->coerceformat = COERCE_IMPLICIT_CAST;
5020 vals->elements = lappend(vals->elements, (Node *) cio);
5022 vals->location = -1;
5024 fe = makeNode(FuncExpr);
5025 fe->funcid = fcl->oid;
5027 fe->funcretset =
false;
5028 fe->funcvariadic =
false;
5029 fe->args = list_make4(desc_c, hv_c, (Expr *) vals, fallback);
5043 const char *desc, List *head_var_idx,
5044 List *head_exprs, Expr *fallback)
5047 list_make2(makeString(
"provsql"), makeString(
"ucq_mobius_provenance_answer")),
5048 4, NIL,
false,
false,
5051 Const *desc_c, *hv_c;
5055 int n = list_length(head_var_idx), i;
5059 if (fcl == NULL || head_var_idx == NIL)
5062 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
5063 desc_c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
5065 hd = palloc(n *
sizeof(Datum));
5067 foreach (lc, head_var_idx)
5068 hd[i++] = Int32GetDatum(lfirst_int(lc));
5069 arr = construct_array(hd, n, INT4OID,
sizeof(int32),
true,
TYPALIGN_INT);
5070 hv_c = makeConst(INT4ARRAYOID, -1, InvalidOid, -1,
5071 PointerGetDatum(arr),
false,
false);
5073 vals = makeNode(ArrayExpr);
5074 vals->array_typeid = TEXTARRAYOID;
5075 vals->element_typeid = TEXTOID;
5076 vals->multidims =
false;
5077 vals->elements = NIL;
5078 foreach (lc, head_exprs) {
5079 CoerceViaIO *cio = makeNode(CoerceViaIO);
5080 cio->arg = (Expr *) lfirst(lc);
5081 cio->resulttype = TEXTOID;
5082 cio->resultcollid = DEFAULT_COLLATION_OID;
5083 cio->coerceformat = COERCE_IMPLICIT_CAST;
5085 vals->elements = lappend(vals->elements, (Node *) cio);
5087 vals->location = -1;
5089 fe = makeNode(FuncExpr);
5090 fe->funcid = fcl->oid;
5092 fe->funcretset =
false;
5093 fe->funcvariadic =
false;
5094 fe->args = list_make4(desc_c, hv_c, (Expr *) vals, fallback);
5108 list_make2(makeString(
"provsql"), makeString(
"mobius_or_null")),
5109 1, NIL,
false,
false,
5116 fe = makeNode(FuncExpr);
5117 fe->funcid = fcl->oid;
5119 fe->funcretset =
false;
5120 fe->funcvariadic =
false;
5121 fe->args = list_make1(mobius_call);
5146 Expr *mobius_call, Expr *joint_call,
5152 if (mobius_call == NULL)
5153 return (joint_call != NULL) ? joint_call : lineage;
5157 ce = makeNode(CoalesceExpr);
5159 ce->coalescecollid = InvalidOid;
5162 ce->args = list_make2(first, (joint_call != NULL) ? joint_call : lineage);
5216 List *prov_atts,
bool aggregation,
5217 bool group_by_rewrite,
5219 int nbcols,
bool wrap_assumed,
5220 bool in_boolean_rewrite,
5221 const char *inv_cert) {
5226 char *jw_desc = NULL;
5227 bool jw_all_exist =
false;
5228 List *jw_head_idx = NIL;
5229 List *jw_head_exprs = NIL;
5242 op !=
SR_PLUS && (aggregation || group_by_rewrite) &&
5243 !in_boolean_rewrite && inv_cert == NULL)
5245 &jw_head_idx, &jw_head_exprs);
5248 result = linitial(prov_atts);
5250 if (
my_lnext(prov_atts, list_head(prov_atts)) == NULL) {
5251 result = linitial(prov_atts);
5253 FuncExpr *expr = makeNode(FuncExpr);
5255 ArrayExpr *array = makeNode(ArrayExpr);
5258 expr->funcvariadic =
true;
5262 array->elements = prov_atts;
5263 array->location = -1;
5265 expr->args = list_make1(array);
5268 expr->args = prov_atts;
5271 expr->location = -1;
5273 result = (Expr *)expr;
5276 if (group_by_rewrite || aggregation) {
5277 Aggref *agg = makeNode(Aggref);
5278 FuncExpr *plus = makeNode(FuncExpr);
5279 TargetEntry *te_inner = makeNode(TargetEntry);
5283 te_inner->resno = 1;
5284 te_inner->expr = (Expr *)result;
5288 agg->args = list_make1(te_inner);
5289 agg->aggkind = AGGKIND_NORMAL;
5291#if PG_VERSION_NUM >= 140000
5292 agg->aggno = agg->aggtransno = -1;
5295 agg->aggargtypes = list_make1_oid(constants->
OID_TYPE_UUID);
5298 plus->args = list_make1(agg);
5300 plus->location = -1;
5302 result = (Expr *)plus;
5315 bool lift_having = q->havingQual != NULL &&
5318 if (aggregation && !lift_having) {
5319 if (q->groupClause == NIL && q->groupingSets == NIL) {
5330 FuncExpr *oneExpr = makeNode(FuncExpr);
5333 oneExpr->args = NIL;
5334 oneExpr->location = -1;
5335 result = (Expr *)oneExpr;
5337 FuncExpr *deltaExpr = makeNode(FuncExpr);
5341 deltaExpr->args = list_make1(result);
5343 deltaExpr->location = -1;
5345 result = (Expr *)deltaExpr;
5377 Expr *group_plus = result;
5379 (Expr *) q->havingQual, constants,
false);
5381 if (!aggregation && !group_by_rewrite && op ==
SR_TIMES &&
5385 FuncExpr *combine = makeNode(FuncExpr);
5386 ArrayExpr *array = makeNode(ArrayExpr);
5392 array->elements = list_copy(prov_atts);
5393 array->location = -1;
5396 combine->location = -1;
5399 combine->args = list_make2(cmp, array);
5401 array->elements = lappend(array->elements, cmp);
5403 combine->funcvariadic =
true;
5404 combine->args = list_make1(array);
5407 result = (Expr *) combine;
5408 }
else if (!entails && aggregation) {
5412 FuncExpr *deltaExpr = makeNode(FuncExpr);
5413 FuncExpr *times = makeNode(FuncExpr);
5414 ArrayExpr *array = makeNode(ArrayExpr);
5417 deltaExpr->args = list_make1(group_plus);
5419 deltaExpr->location = -1;
5423 array->elements = list_make2(deltaExpr, cmp);
5424 array->location = -1;
5428 times->funcvariadic =
true;
5429 times->args = list_make1(array);
5430 times->location = -1;
5432 result = (Expr *) times;
5437 q->havingQual = NULL;
5447 foreach (lc, q->jointree->fromlist) {
5448 if (IsA(lfirst(lc), JoinExpr)) {
5449 JoinExpr *je = (JoinExpr *)lfirst(lc);
5461 ArrayExpr *array = makeNode(ArrayExpr);
5462 FuncExpr *fe = makeNode(FuncExpr);
5463 bool projection =
false;
5477 int *prov_offset = (
int *)palloc0((q->rtable->length + 1) *
sizeof(
int));
5482 fe->funcvariadic =
true;
5488 array->elements = NIL;
5489 array->location = -1;
5491 for (r = 1; r <= (Index)q->rtable->length; ++r) {
5492 prov_offset[r] = cum;
5494 RangeTblEntry *rte_r = (RangeTblEntry *)list_nth(q->rtable, r-1);
5495 int ncols = list_length(rte_r->eref->colnames);
5496 bool is_prov =
false;
5499 for (k = 0; k < ncols; ++k) {
5500 if (columns[r-1][k] == -1) is_prov =
true;
5501 else if (columns[r-1][k] > 0) nb_user++;
5503 if (is_prov) cum += nb_user;
5507 foreach (lc_v, q->targetList) {
5508 TargetEntry *te_v = (TargetEntry *)lfirst(lc_v);
5509 if (IsA(te_v->expr, Var)) {
5510 Var *vte_v = (Var *)te_v->expr;
5511 RangeTblEntry *rte_v =
5512 (RangeTblEntry *)lfirst(list_nth_cell(q->rtable, vte_v->varno - 1));
5514#if PG_VERSION_NUM >= 180000
5515 if (rte_v->rtekind == RTE_GROUP) {
5516 Expr *ge = lfirst(list_nth_cell(rte_v->groupexprs, vte_v->varattno - 1));
5518 Var *v = (Var *) ge;
5519 value_v = columns[v->varno - 1] ?
5520 columns[v->varno - 1][v->varattno - 1] : 0;
5522 Const *ce = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
5523 sizeof(int32), Int32GetDatum(0),
false,
true);
5525 array->elements = lappend(array->elements, ce);
5530 if (rte_v->rtekind != RTE_JOIN) {
5531 if (rte_v->rtekind == RTE_RELATION && columns[vte_v->varno - 1]) {
5535 bool is_prov =
false;
5536 int ncols_rte = list_length(rte_v->eref->colnames);
5537 for (
int k = 0; k < ncols_rte; k++) {
5538 if (columns[vte_v->varno - 1][k] == -1) {
5544 int raw = columns[vte_v->varno - 1][vte_v->varattno - 1];
5552 value_v = (raw == -1) ? -1
5553 : (int)vte_v->varattno
5554 + prov_offset[vte_v->varno];
5563 sizeof(int32), Int32GetDatum(0),
false,
true);
5564 array->elements = lappend(array->elements, ce);
5572 value_v = columns[vte_v->varno - 1] ?
5573 columns[vte_v->varno - 1][vte_v->varattno - 1] : 0;
5576 Var *jav_v = (Var *)lfirst(
5577 list_nth_cell(rte_v->joinaliasvars, vte_v->varattno - 1));
5578 if (jav_v && IsA(jav_v, Var) && columns[jav_v->varno - 1]) {
5579 RangeTblEntry *jrte_v = (RangeTblEntry *)lfirst(
5580 list_nth_cell(q->rtable, jav_v->varno - 1));
5581 if (jrte_v->rtekind == RTE_RELATION) {
5584 bool is_prov =
false;
5585 int ncols_jrte = list_length(jrte_v->eref->colnames);
5586 for (
int k = 0; k < ncols_jrte; k++) {
5587 if (columns[jav_v->varno - 1][k] == -1) {
5593 int raw = columns[jav_v->varno - 1][jav_v->varattno - 1];
5594 value_v = (raw == -1) ? -1
5595 : (int)jav_v->varattno
5596 + prov_offset[jav_v->varno];
5600 sizeof(int32), Int32GetDatum(0),
false,
true);
5601 array->elements = lappend(array->elements, ce);
5606 value_v = columns[jav_v->varno - 1][jav_v->varattno - 1];
5616 makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
5617 Int32GetDatum(value_v),
false,
true);
5619 array->elements = lappend(array->elements, ce);
5621 if (value_v != ++nb_column)
5628 Const *ce = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
5629 sizeof(int32), Int32GetDatum(0),
false,
true);
5631 array->elements = lappend(array->elements, ce);
5636 if (nb_column != nbcols)
5640 fe->args = list_make2(result, array);
5641 result = (Expr *)fe;
5666 if (inv_cert != NULL &&
5681 if (jw_desc != NULL && jw_all_exist) {
5697 }
else if (jw_desc != NULL && jw_head_idx != NIL && inv_cert == NULL) {
5706 jw_head_exprs, result)
5710 jw_head_exprs, result)
5722#if PG_VERSION_NUM >= 180000
5724 Index group_rtindex;
5726} resolve_group_rte_ctx;
5729resolve_group_rte_vars_mutator(Node *node,
void *raw_ctx) {
5730 resolve_group_rte_ctx *ctx = (resolve_group_rte_ctx *)raw_ctx;
5733 if (IsA(node, Var)) {
5734 Var *v = (Var *)node;
5735 if (v->varno == ctx->group_rtindex) {
5736 Node *resolved = copyObject(list_nth(ctx->groupexprs, v->varattno - 1));
5737#if PG_VERSION_NUM >= 160000
5743 if (IsA(resolved, Var))
5744 ((Var *)resolved)->varnullingrels = NULL;
5749 return expression_tree_mutator(node, resolve_group_rte_vars_mutator, raw_ctx);
5767 resolve_group_rte_ctx grp_ctx;
5773 if (!q->hasGroupRTE)
5776 foreach (lc, q->rtable) {
5777 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
5778 if (r->rtekind == RTE_GROUP) {
5779 grp_ctx.group_rtindex = idx;
5780 grp_ctx.groupexprs = r->groupexprs;
5791 q->rtable = list_truncate(q->rtable, rte_len);
5792 q->hasGroupRTE =
false;
5794 foreach (lc, q->targetList) {
5795 TargetEntry *te = (TargetEntry *) lfirst(lc);
5796 te->expr = (Expr *) resolve_group_rte_vars_mutator(
5797 (Node *) te->expr, &grp_ctx);
5799 if (q->jointree && q->jointree->quals)
5800 q->jointree->quals = resolve_group_rte_vars_mutator(
5801 q->jointree->quals, &grp_ctx);
5811 q->havingQual = resolve_group_rte_vars_mutator(q->havingQual, &grp_ctx);
5834 List *groupby_tes) {
5839 int resno = 1, sgref = 1;
5841 inner = copyObject(q);
5843 inner->hasAggs =
false;
5844 inner->sortClause = NIL;
5845 inner->limitCount = NULL;
5846 inner->limitOffset = NULL;
5847 inner->distinctClause = NIL;
5848 inner->hasDistinctOn =
false;
5849 inner->havingQual = NULL;
5853 TargetEntry *kte = makeNode(TargetEntry);
5854 SortGroupClause *sgc = makeNode(SortGroupClause);
5856 kte->expr = copyObject(key_expr);
5857 kte->resno = resno++;
5858 kte->resname =
"key";
5859 sgc->tleSortGroupRef = kte->ressortgroupref = sgref++;
5860 get_sort_group_operators(exprType((Node *)kte->expr),
true,
true,
false,
5861 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
5862 new_gc = list_make1(sgc);
5863 new_tl = list_make1(kte);
5867 foreach (lc, groupby_tes) {
5868 TargetEntry *gyte = copyObject((TargetEntry *)lfirst(lc));
5869 SortGroupClause *sgc = makeNode(SortGroupClause);
5871 gyte->resno = resno++;
5872 gyte->resjunk =
false;
5873 sgc->tleSortGroupRef = gyte->ressortgroupref = sgref++;
5874 get_sort_group_operators(exprType((Node *)gyte->expr),
true,
true,
false,
5875 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
5876 new_gc = lappend(new_gc, sgc);
5877 new_tl = lappend(new_tl, gyte);
5880 inner->targetList = new_tl;
5881 inner->groupClause = new_gc;
5904 Query *inner,
int n_gb,
5906 Query *outer = makeNode(Query);
5907 RangeTblEntry *rte = makeNode(RangeTblEntry);
5908 Alias *alias = makeNode(Alias), *eref = makeNode(Alias);
5909 RangeTblRef *rtr = makeNode(RangeTblRef);
5910 FromExpr *jt = makeNode(FromExpr);
5911 List *new_tl = NIL, *new_gc = NIL;
5913 int resno = 1, sgref = 1;
5914 int inner_len = list_length(inner->targetList);
5918 alias->aliasname = eref->aliasname =
"d";
5919 eref->colnames = NIL;
5920 foreach (lc, inner->targetList) {
5921 TargetEntry *te = lfirst(lc);
5922 eref->colnames = lappend(eref->colnames,
5923 makeString(te->resname ? pstrdup(te->resname) :
""));
5927 rte->rtekind = RTE_SUBQUERY;
5928 rte->subquery = inner;
5929 rte->inFromCl =
true;
5930#if PG_VERSION_NUM < 160000
5931 rte->requiredPerms = ACL_SELECT;
5935 jt->fromlist = list_make1(rtr);
5937 outer->commandType = CMD_SELECT;
5938 outer->canSetTag =
true;
5939 outer->rtable = list_make1(rte);
5940 outer->jointree = jt;
5941 outer->hasAggs =
true;
5945 TargetEntry *agg_te = copyObject(orig_agg_te);
5946 Aggref *ar = (Aggref *)agg_te->expr;
5947 Var *key_var = makeNode(Var);
5948 TargetEntry *arg_te = makeNode(TargetEntry);
5951 key_var->varattno = 1;
5952 key_var->vartype = linitial_oid(ar->aggargtypes);
5953 key_var->varcollid = exprCollation((Node *)((TargetEntry *)linitial(ar->args))->expr);
5954 key_var->vartypmod = -1;
5955 key_var->location = -1;
5957 arg_te->expr = (Expr *)key_var;
5959 ar->args = list_make1(arg_te);
5960 ar->aggdistinct = NIL;
5961 agg_te->resno = resno++;
5962 new_tl = list_make1(agg_te);
5966 for (attno = inner_len - n_gb + 1; attno <= inner_len; attno++) {
5967 TargetEntry *inner_te = list_nth(inner->targetList, attno - 1);
5968 Var *gb_var = makeNode(Var);
5969 TargetEntry *gb_te = makeNode(TargetEntry);
5970 SortGroupClause *sgc = makeNode(SortGroupClause);
5973 gb_var->varattno = attno;
5974 gb_var->vartype = exprType((Node *)inner_te->expr);
5975 gb_var->varcollid = exprCollation((Node *)inner_te->expr);
5976 gb_var->vartypmod = -1;
5977 gb_var->location = -1;
5979 gb_te->resno = resno++;
5980 gb_te->expr = (Expr *)gb_var;
5981 gb_te->resname = inner_te->resname;
5983 sgc->tleSortGroupRef = gb_te->ressortgroupref = sgref++;
5984 sgc->nulls_first =
false;
5985 get_sort_group_operators(gb_var->vartype,
true,
true,
false,
5986 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
5987 new_gc = lappend(new_gc, sgc);
5988 new_tl = lappend(new_tl, gb_te);
5991 outer->targetList = new_tl;
5992 outer->groupClause = new_gc;
6011 if (IsA(node, Aggref)) {
6012 Aggref *ar = (Aggref *) node;
6013 if (list_length(ar->aggdistinct) > 0)
6037 if (IsA(node, Aggref)) {
6038 Aggref *ar = (Aggref *) node;
6039 if (list_length(ar->aggdistinct) > 0) {
6041 Var *v = makeNode(Var);
6044 v->vartype = ar->aggtype;
6046 v->varcollid = ar->aggcollid;
6077 List *distinct_agg_tes = NIL;
6078 List *groupby_tes = NIL;
6082#if PG_VERSION_NUM >= 180000
6102 foreach (lc, q->targetList) {
6103 TargetEntry *te = lfirst(lc);
6104 if (IsA(te->expr, Aggref)) {
6105 Aggref *ar = (Aggref *)te->expr;
6106 if (list_length(ar->aggdistinct) > 0)
6107 distinct_agg_tes = lappend(distinct_agg_tes, te);
6109 (
void *)constants)) {
6114 TargetEntry *te_copy = copyObject(te);
6115 te_copy->resjunk =
false;
6116 groupby_tes = lappend(groupby_tes, te_copy);
6123 if (q->havingQual != NULL)
6126 if (distinct_agg_tes == NIL && hctx.
aggs == NIL)
6130 int n_having = list_length(hctx.
aggs);
6131 int n_aggs = list_length(distinct_agg_tes) + n_having;
6132 int n_gb = list_length(groupby_tes);
6133 List *outer_queries = NIL;
6150 foreach (lc, distinct_agg_tes) {
6151 TargetEntry *agg_te = lfirst(lc);
6152 Aggref *ar = (Aggref *)agg_te->expr;
6153 if(list_length(ar->args) != 1)
6154 provsql_error(
"AGG(DISTINCT) with more than one argument is not supported");
6156 Expr *key_expr = (Expr *)((TargetEntry *)linitial(ar->args))->expr;
6159 outer_queries = lappend(outer_queries, outer);
6166 foreach (lc, hctx.
aggs) {
6167 Aggref *ar = lfirst(lc);
6168 if(list_length(ar->args) != 1)
6169 provsql_error(
"AGG(DISTINCT) with more than one argument is not supported");
6171 TargetEntry *syn = makeNode(TargetEntry);
6172 Expr *key_expr = (Expr *)((TargetEntry *)linitial(ar->args))->expr;
6175 syn->expr = (Expr *) copyObject(ar);
6178 outer_queries = lappend(outer_queries, outer);
6190 int rtable_base = list_length(q->rtable);
6192 foreach (lc, outer_queries) {
6193 Query *oq = lfirst(lc);
6194 RangeTblEntry *rte = makeNode(RangeTblEntry);
6195 Alias *alias = makeNode(Alias), *eref = makeNode(Alias);
6199 snprintf(buf,
sizeof(buf),
"d%d", i + 1);
6200 alias->aliasname = eref->aliasname = pstrdup(buf);
6201 eref->colnames = NIL;
6202 foreach (lc2, oq->targetList) {
6203 TargetEntry *te = lfirst(lc2);
6204 eref->colnames = lappend(eref->colnames,
6205 makeString(te->resname ? pstrdup(te->resname) :
""));
6209 rte->rtekind = RTE_SUBQUERY;
6211 rte->inFromCl =
true;
6212#if PG_VERSION_NUM < 160000
6213 rte->requiredPerms = ACL_SELECT;
6215 q->rtable = lappend(q->rtable, rte);
6222 FromExpr *jt = q->jointree;
6223 List *from_list = jt->fromlist;
6224 List *where_args = NIL;
6226 for (i = rtable_base + 1; i <= rtable_base + n_aggs; i++) {
6227 RangeTblRef *rtr = makeNode(RangeTblRef);
6232 from_list = lappend(from_list, rtr);
6235 foreach(lc2, groupby_tes) {
6236 TargetEntry *gb_te = lfirst(lc2);
6237 int gb_attno = ++j + 1;
6238 Oid ytype = exprType((Node *)gb_te->expr);
6240 Operator opInfo = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
6241 Form_pg_operator opform;
6242 OpExpr *oe = makeNode(OpExpr);
6243 Expr *le = copyObject(gb_te->expr);
6244 Var *rv = makeNode(Var);
6245 Oid collation=exprCollation((Node*) le);
6247 if (!HeapTupleIsValid(opInfo))
6248 provsql_error(
"could not find equality operator for type %u",
6250 opform = (Form_pg_operator)GETSTRUCT(opInfo);
6253 oe->opfuncid = opform->oprcode;
6254 oe->opresulttype = opform->oprresult;
6255 oe->opcollid = InvalidOid;
6256 oe->inputcollid = collation;
6258 ReleaseSysCache(opInfo);
6260 rv->varno = i; rv->varattno = gb_attno;
6261 rv->vartype = ytype; rv->varcollid = collation;
6262 rv->vartypmod = -1; rv->location = -1;
6264 oe->args = list_make2(le, rv);
6265 where_args = lappend(where_args, oe);
6269 if (list_length(where_args) == 0) {
6271 }
else if (list_length(where_args) == 1) {
6272 jt->quals = linitial(where_args);
6274 BoolExpr *be = makeNode(BoolExpr);
6275 be->boolop = AND_EXPR;
6276 be->args = where_args;
6278 jt->quals = (Node *)be;
6285 int agg_idx = rtable_base + 1;
6288 foreach (lc2, q->targetList) {
6289 TargetEntry *te = lfirst(lc2);
6291 if (IsA(te->expr, Aggref) &&
6292 ((Aggref *)te->expr)->aggdistinct != NIL) {
6293 Var *v = makeNode(Var);
6294 v->varno = agg_idx++;
6298 te->expr = (Expr*)v;
6309 hrc.
next_rtindex = rtable_base + (n_aggs - n_having) + 1;
6343 if (IsA(node, Aggref)) {
6344 Aggref *ar_v = (Aggref *)node;
6363 Const *typ_const = (Const *)lsecond(prov_agg->args);
6364 Oid target_type = DatumGetObjectId(typ_const->constvalue);
6365 CoercionPathType pathtype;
6368 pathtype = find_coercion_pathway(target_type,
6370 COERCION_EXPLICIT, &castfuncid);
6371 if (pathtype == COERCION_PATH_FUNC && OidIsValid(castfuncid)) {
6372 FuncExpr *cast = makeNode(FuncExpr);
6373 cast->funcid = castfuncid;
6374 cast->funcresulttype = target_type;
6375 cast->funcretset =
false;
6376 cast->funcvariadic =
false;
6377 cast->funcformat = COERCE_IMPLICIT_CAST;
6378 cast->args = list_make1(prov_agg);
6379 cast->location = -1;
6380 return (Node *)cast;
6383 provsql_error(
"no cast from agg_token to %s for arithmetic on aggregate",
6384 format_type_be(target_type));
6385 return (Node *)prov_agg;
6398 CoercionPathType pathtype;
6402 COERCION_EXPLICIT, &castfuncid);
6403 if (pathtype == COERCION_PATH_FUNC && OidIsValid(castfuncid)) {
6404 FuncExpr *cast = makeNode(FuncExpr);
6405 cast->funcid = castfuncid;
6406 cast->funcresulttype = target_type;
6407 cast->funcretset =
false;
6408 cast->funcvariadic =
false;
6409 cast->funcformat = COERCE_IMPLICIT_CAST;
6410 cast->args = list_make1(arg);
6411 cast->location = -1;
6412 return (Node *)cast;
6415 provsql_error(
"no cast from agg_token to %s for arithmetic on aggregate",
6416 format_type_be(target_type));
6437 Form_pg_proc procForm;
6441 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(parent_funcid));
6442 if (!HeapTupleIsValid(tp))
6444 procForm = (Form_pg_proc) GETSTRUCT(tp);
6448 Node *arg = lfirst(lc);
6459 Oid formal_type = procForm->proargtypes.values[i];
6462 !IsPolymorphicType(formal_type)) {
6463 if (IsA(arg, FuncExpr) &&
6473 ReleaseSysCache(tp);
6486 if (n != NULL && IsA(n, FuncExpr)) {
6487 FuncExpr *fe = (FuncExpr *)n;
6488 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
6489 fe->funcformat == COERCE_EXPLICIT_CAST) &&
6490 list_length(fe->args) == 1) {
6491 n = (Node *)linitial(fe->args);
6494 }
else if (n != NULL && IsA(n, RelabelType)) {
6495 n = (Node *)((RelabelType *)n)->arg;
6519 int nargs = list_length(op->args);
6520 Node *l, *r, *lp, *rp;
6524 if (nargs < 1 || nargs > 2)
6526 opname = get_opname(op->opno);
6529 is_arith = strcmp(opname,
"+") == 0 || strcmp(opname,
"-") == 0 ||
6530 strcmp(opname,
"*") == 0 || strcmp(opname,
"/") == 0;
6537 l = (Node *)linitial(op->args);
6538 r = (Node *)lsecond(op->args);
6541 r = (Node *)linitial(op->args);
6560 pstate = make_parsestate(NULL);
6561 newop = make_op(pstate, list_make1(makeString(opname)), l, r, NULL, -1);
6562 free_parsestate(pstate);
6564 return (Node *)newop;
6594 if (IsA(result, OpExpr)) {
6595 OpExpr *op = (OpExpr *)result;
6597 if (swapped != NULL)
6601 }
else if (IsA(result, FuncExpr)) {
6602 FuncExpr *fe = (FuncExpr *)result;
6605 }
else if (IsA(result, CaseExpr)) {
6615 CaseExpr *ce = (CaseExpr *)result;
6618 foreach (lc, ce->args) {
6619 CaseWhen *cw = (CaseWhen *)lfirst(lc);
6622 (Node *)cw->result, ce->casetype, constants);
6624 if (ce->defresult != NULL &&
6627 (Node *)ce->defresult, ce->casetype, constants);
6651 char *opname = get_opname(op->opno);
6652 int nargs = list_length(op->args);
6653 Node *l = NULL, *r = NULL, *aggn = NULL, *cn = NULL, *old_arg, *new_arg = NULL;
6656 bool agg_left =
true, plus, minus, times;
6657 bool is_sum, is_avg, is_min, is_max;
6661 plus = strcmp(opname,
"+") == 0;
6662 minus = strcmp(opname,
"-") == 0;
6663 times = strcmp(opname,
"*") == 0;
6664 if (!(plus || minus || times))
6671 }
else if (nargs == 2) {
6674 if (IsA(l, Aggref) && IsA(r, Const)) { aggn = l; cn = r; agg_left =
true; }
6675 else if (IsA(r, Aggref) && IsA(l, Const)) { aggn = r; cn = l; agg_left =
false; }
6680 if (!IsA(aggn, Aggref))
6682 ar = (Aggref *)aggn;
6685 if (ar->aggstar || list_length(ar->args) != 1 ||
6686 ar->aggdistinct != NIL || ar->aggfilter != NULL || ar->aggorder != NIL)
6692 aggnm = get_func_name(ar->aggfnoid);
6695 is_sum = strcmp(aggnm,
"sum") == 0; is_avg = strcmp(aggnm,
"avg") == 0;
6696 is_min = strcmp(aggnm,
"min") == 0; is_max = strcmp(aggnm,
"max") == 0;
6698 if (!(is_sum || is_avg || is_min || is_max))
6701 old_arg = (Node *)((TargetEntry *)linitial(ar->args))->expr;
6704 if (is_sum || is_avg)
6707 if (is_sum || is_avg)
6708 new_arg = agg_left ?
build_binop(
"*", old_arg, cn)
6711 if (is_avg || is_min || is_max)
6712 new_arg = agg_left ?
build_binop(
"+", old_arg, cn)
6716 if (is_avg || is_min || is_max)
6723 if (new_arg == NULL)
6727 if (exprType(new_arg) != exprType(old_arg))
6730 newar = (Aggref *)copyObject(ar);
6731 ((TargetEntry *)linitial(newar->args))->expr = (Expr *)new_arg;
6732 return (Node *)newar;
6740 if (IsA(node, OpExpr)) {
6763 Query *q, List *prov_atts,
6769 bool is_scalar = (q->groupClause == NIL && q->groupingSets == NIL);
6777 QTW_DONT_COPY_QUERY | QTW_IGNORE_RT_SUBQUERIES);
6780 QTW_DONT_COPY_QUERY | QTW_IGNORE_RT_SUBQUERIES);
6787 foreach(lc, q->targetList) {
6788 TargetEntry *te = (TargetEntry *)lfirst(lc);
6789 if (te->expr == NULL)
6792 if (IsA(te->expr, FuncExpr) &&
6811 TargetEntry *newte = makeNode(TargetEntry);
6812 bool inserted =
false;
6819 RangeTblEntry *rte = list_nth(q->rtable, ((Var *)
provenance)->varno - 1);
6820 newte->resorigtbl = rte->relid;
6821 newte->resorigcol = ((Var *)
provenance)->varattno;
6825 for (ListCell *cell = list_head(q->targetList); cell != NULL;) {
6826 TargetEntry *te = (TargetEntry *)lfirst(cell);
6833 newte->resno = resno;
6835 cell = list_nth_cell(q->targetList, resno);
6836 te = (TargetEntry *)lfirst(cell);
6843 cell =
my_lnext(q->targetList, cell);
6847 newte->resno = resno + 1;
6848 q->targetList = lappend(q->targetList, newte);
6876 if (IsA(node, Aggref))
6893 if (IsA(node, Aggref)) {
6906 if (IsA(node, FuncExpr)) {
6907 FuncExpr *f = (FuncExpr *)node;
6912 "applying an SQL aggregate on top of a ProvSQL-introduced "
6913 "aggregation is not supported: the inner provenance() would "
6914 "be substituted with an expression containing an aggregate, "
6915 "producing a nested same-level aggregate that PostgreSQL "
6916 "rejects. Evaluate the per-row provenance in a subquery "
6917 "and aggregate the resulting scalar outside, or drop the "
6918 "surrounding aggregate.");
6920 return (Node *)copyObject(context->
provsql);
6922 }
else if (IsA(node, RangeTblEntry) || IsA(node, RangeTblFunction)) {
6954 QTW_DONT_COPY_QUERY | QTW_IGNORE_RT_SUBQUERIES);
6971 Bitmapset *already_in_group_by = NULL;
6973 foreach (lc, q->groupClause) {
6974 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc);
6975 already_in_group_by =
6976 bms_add_member(already_in_group_by, sgc->tleSortGroupRef);
6979 foreach (lc, q->distinctClause) {
6980 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc);
6981 if (!bms_is_member(sgc->tleSortGroupRef, already_in_group_by)) {
6982 q->groupClause = lappend(q->groupClause, sgc);
6986 q->distinctClause = NULL;
7009 if (!q->distinctClause)
7011 if (q->hasDistinctOn)
7013 else if (q->hasAggs)
7014 provsql_error(
"DISTINCT on aggregate results not supported");
7015 else if (list_length(q->distinctClause) < list_length(q->targetList))
7016 provsql_error(
"Inconsistent DISTINCT and GROUP BY clauses not "
7034 const Bitmapset *removed_sortgrouprefs) {
7035 List **lists[3] = {&q->groupClause, &q->distinctClause, &q->sortClause};
7038 for (i = 0; i < 3; ++i) {
7039 ListCell *cell, *prev;
7041 for (cell = list_head(*lists[i]), prev = NULL; cell != NULL;) {
7042 SortGroupClause *sgc = (SortGroupClause *)lfirst(cell);
7043 if (bms_is_member(sgc->tleSortGroupRef, removed_sortgrouprefs)) {
7049 cell = list_head(*lists[i]);
7071 SetOperationStmt *so = (SetOperationStmt *)q->setOperations;
7072 List **lists[3] = {&so->colTypes, &so->colTypmods, &so->colCollations};
7075 for (i = 0; i < 3; ++i) {
7076 ListCell *cell, *prev;
7079 for (cell = list_head(*lists[i]), prev = NULL, j = 0; cell != NULL; ++j) {
7086 cell = list_head(*lists[i]);
7112 Query *new_query = makeNode(Query);
7113 RangeTblEntry *rte = makeNode(RangeTblEntry);
7114 FromExpr *jointree = makeNode(FromExpr);
7115 RangeTblRef *rtr = makeNode(RangeTblRef);
7117 SetOperationStmt *stmt = (SetOperationStmt *)q->setOperations;
7120 int sortgroupref = 0;
7128 rte->rtekind = RTE_SUBQUERY;
7130 rte->eref = copyObject(((RangeTblEntry *)linitial(q->rtable))->eref);
7131 rte->inFromCl =
true;
7132#if PG_VERSION_NUM < 160000
7135 rte->requiredPerms = ACL_SELECT;
7139 jointree->fromlist = list_make1(rtr);
7141 new_query->commandType = CMD_SELECT;
7142 new_query->canSetTag =
true;
7143 new_query->rtable = list_make1(rte);
7144 new_query->jointree = jointree;
7145 new_query->targetList = copyObject(q->targetList);
7147 if (new_query->targetList) {
7148 foreach (lc, new_query->targetList) {
7149 TargetEntry *te = (TargetEntry *)lfirst(lc);
7150 SortGroupClause *sgc = makeNode(SortGroupClause);
7152 sgc->tleSortGroupRef = te->ressortgroupref = ++sortgroupref;
7154 get_sort_group_operators(exprType((Node *)te->expr),
false,
true,
false,
7155 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
7157 new_query->groupClause = lappend(new_query->groupClause, sgc);
7160 GroupingSet *gs = makeNode(GroupingSet);
7161 gs->kind = GROUPING_SET_EMPTY;
7164 new_query->groupingSets = list_make1(gs);
7188 if (IsA(node, FuncExpr)) {
7189 FuncExpr *f = (FuncExpr *)node;
7214 Bitmapset *group_refs = NULL;
7215 foreach (lc, q->groupClause) {
7216 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc);
7217 group_refs = bms_add_member(group_refs, sgc->tleSortGroupRef);
7220 foreach (lc, q->targetList) {
7221 TargetEntry *te = (TargetEntry *)lfirst(lc);
7222 if (te->ressortgroupref > 0 &&
7223 bms_is_member(te->ressortgroupref, group_refs)) {
7225 (
void *)constants)) {
7229#if PG_VERSION_NUM >= 180000
7232 if(IsA(te->expr, Var)) {
7233 Var *v = (Var *) te->expr;
7234 RangeTblEntry *r = (RangeTblEntry *)list_nth(q->rtable, v->varno - 1);
7235 if(r->rtekind == RTE_GROUP)
7237 (
void *)constants)) {
7270 if (IsA(node, OpExpr)) {
7271 OpExpr *op = (OpExpr *)node;
7276 if (IsA(node, FuncExpr)) {
7277 FuncExpr *f = (FuncExpr *)node;
7285 if (IsA(node, MinMaxExpr)) {
7286 MinMaxExpr *mm = (MinMaxExpr *)node;
7291 if (IsA(node, SubLink)) {
7292 SubLink *sl = (SubLink *)node;
7298 if (IsA(node, Query))
7349 return sl != NULL && sl->subselect && IsA(sl->subselect, Query) &&
7367 TargetEntry *only = NULL;
7369 if (sub == NULL || !IsA(sub, Query))
7371 foreach (lc, sub->targetList) {
7372 TargetEntry *te = (TargetEntry *)lfirst(lc);
7379 return only != NULL && IsA(only->expr, FuncExpr) &&
7388 if (IsA(node, SubLink)) {
7389 SubLink *sl = (SubLink *)node;
7390 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
7391 IsA(sl->subselect, Query) &&
7393 (Query *)sl->subselect))
7395 return expression_tree_walker((Node *)sl->testexpr,
7398 if (IsA(node, Query))
7412 if (q->havingQual &&
7422 if (IsA(node, SubLink)) {
7423 SubLink *sl = (SubLink *)node;
7424 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
7425 IsA(sl->subselect, Query) &&
7428 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
7429 IsA(sl->subselect, Query)) {
7430 Query *sub = (Query *)sl->subselect;
7431 if (!sub->hasAggs && !sub->groupClause && !sub->groupingSets &&
7432 !sub->distinctClause && !sub->setOperations && !sub->hasWindowFuncs &&
7433 !sub->hasSubLinks && !sub->limitCount && !sub->limitOffset &&
7434 !sub->cteList && list_length(sub->rtable) == 1 &&
7435 list_length(sub->targetList) == 1 && sub->jointree &&
7436 list_length(sub->jointree->fromlist) == 1 &&
7437 IsA(linitial(sub->jointree->fromlist), RangeTblRef)) {
7438 RangeTblEntry *qr = (RangeTblEntry *)linitial(sub->rtable);
7439 if (qr->rtekind == RTE_RELATION) {
7442 foreach (lc, qr->eref->colnames) {
7453 if (IsA(node, Query))
7463 if (IsA(node, Query)) {
7464 Query *q = (Query *)node;
7470 foreach (rc, q->cteList) {
7471 CommonTableExpr *cte = (CommonTableExpr *)lfirst(rc);
7511 foreach (rc, q->rtable) {
7512 RangeTblEntry *r = (RangeTblEntry *)lfirst(rc);
7513 if (r->rtekind == RTE_RELATION) {
7515 AttrNumber attid = 1;
7517 foreach (lc, r->eref->colnames) {
7518 const char *v = strVal(lfirst(lc));
7527 }
else if (r->rtekind == RTE_FUNCTION) {
7529 AttrNumber attid = 1;
7531 foreach (lc, r->functions) {
7532 RangeTblFunction *func = (RangeTblFunction *)lfirst(lc);
7534 if (func->funccolcount == 1) {
7535 FuncExpr *expr = (FuncExpr *)func->funcexpr;
7537 !strcmp(get_rte_attribute_name(r, attid),
7543 attid += func->funccolcount;
7545 }
else if (r->rtekind == RTE_SUBQUERY && r->subquery != NULL) {
7595 if (node == NULL || c->
found)
7597 if (IsA(node, SubLink)) {
7598 SubLink *sl = (SubLink *)node;
7599 if (IsA(sl->subselect, Query) &&
7607 if (IsA(node, Query))
7629 if (!c.
found && q->jointree)
7631 if (!c.
found && q->havingQual)
7653 if (IsA(node, SubLink)) {
7655 *out = lappend(*out, node);
7658 if (IsA(node, BoolExpr)) {
7660 foreach (lc, ((BoolExpr *)node)->args)
7664 if (IsA(node, OpExpr)) {
7668 foreach (lc, ((OpExpr *)node)->args) {
7669 Node *a = (Node *)lfirst(lc);
7670 if (IsA(a, RelabelType))
7671 a = (Node *)((RelabelType *)a)->arg;
7672 if (IsA(a, SubLink))
7673 *out = lappend(*out, a);
7686#define PROVSQL_JOIN_ALIAS "provsql_join"
7708 if (IsA(node, SubLink)) {
7709 SubLink *sl = (SubLink *)node;
7710 if (IsA(sl->subselect, Query) &&
7712 if (list_member_ptr(c->
direct, sl) || sl->subLinkType != EXPR_SUBLINK)
7720 if (IsA(node, Query))
7741 foreach (lc, q->targetList) {
7742 Node *e = (Node *)((TargetEntry *)lfirst(lc))->expr;
7743 if (e && IsA(e, RelabelType))
7744 e = (Node *)((RelabelType *)e)->arg;
7745 if (e && IsA(e, SubLink))
7748 if (q->jointree && q->jointree->quals)
7770 if (IsA(node, FuncExpr) &&
7771 ((FuncExpr *)node)->funcid ==
7772 ((
const constants_t *)data)->OID_FUNCTION_PROVENANCE)
7774 if (IsA(node, Query))
7798 if (IsA(node, Query))
7800 if (IsA(node, SubLink)) {
7801 SubLink *sl = (SubLink *)node;
7802 if (sl->subselect && IsA(sl->subselect, Query) &&
7807 if (sl->subLinkType == EXPR_SUBLINK &&
7809 (Query *)sl->subselect))
7829 ListCell *prev = NULL;
7830 int removed_resno = -1;
7832 foreach (lc, q->targetList) {
7833 TargetEntry *te = (TargetEntry *)lfirst(lc);
7835 removed_resno = te->resno;
7842 if (removed_resno < 0)
7845 foreach (lc, q->targetList) {
7846 TargetEntry *te = (TargetEntry *)lfirst(lc);
7847 if (te->resno > removed_resno)
7863 if (IsA(node, Var)) {
7864 Var *v = (Var *) node;
7883 return expression_tree_walker(node,
aggtoken_walker, (
void*) constants);
7907 if (IsA(node, Var)) {
7908 Var *v = (Var *) node;
7913 if (IsA(node, FuncExpr)) {
7914 FuncExpr *fe = (FuncExpr *) node;
7937 (
void *) constants);
7975 if (IsA(expr, BoolExpr)) {
7976 BoolExpr *be = (BoolExpr *) expr;
7980 if (be->boolop == NOT_EXPR)
7982 constants, !negated);
7984 conjunction = (be->boolop == AND_EXPR) ? !negated : negated;
7986 foreach (lc, be->args) {
7988 constants, negated);
7989 if (conjunction && child)
7991 if (!conjunction && !child)
7994 return !conjunction;
8005 char *name = get_func_name(aggfnoid);
8009 yes = strcmp(name,
"bool_or") == 0 || strcmp(name,
"bool_and") == 0 ||
8010 strcmp(name,
"every") == 0;
8024 if (IsA(n, BoolExpr)) {
8025 BoolExpr *be = (BoolExpr *) n;
8027 foreach (lc, be->args)
8031 if (IsA(n, Aggref)) {
8032 Aggref *ar = (Aggref *) n;
8034 OpExpr *eq = makeNode(OpExpr);
8035 eq->opno = BooleanEqualOperator;
8036 eq->opfuncid = get_opcode(BooleanEqualOperator);
8037 eq->opresulttype = BOOLOID;
8038 eq->opretset =
false;
8039 eq->opcollid = InvalidOid;
8040 eq->inputcollid = InvalidOid;
8041 eq->args = list_make2(ar, makeBoolConst(
true,
false));
8069 SetOperationStmt *setOps = (SetOperationStmt *)q->setOperations;
8070 RangeTblEntry *rte = makeNode(RangeTblEntry);
8071 FromExpr *fe = makeNode(FromExpr);
8072 JoinExpr *je = makeNode(JoinExpr);
8073 BoolExpr *expr = makeNode(BoolExpr);
8077 if (!IsA(setOps->larg, RangeTblRef) || !IsA(setOps->rarg, RangeTblRef)) {
8081 expr->boolop = AND_EXPR;
8082 expr->location = -1;
8085 foreach (lc, q->targetList) {
8086 TargetEntry *te = (TargetEntry *)lfirst(lc);
8089 if (!IsA(te->expr, Var))
8092 v = (Var *)te->expr;
8100 DistinctExpr *oe = makeNode(DistinctExpr);
8102 Operator opInfo = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
8103 Form_pg_operator opform;
8104 Var *leftArg, *rightArg;
8106 if (!HeapTupleIsValid(opInfo))
8107 provsql_error(
"could not find operator with OID %u to compare variables of type %u",
8110 opform = (Form_pg_operator)GETSTRUCT(opInfo);
8111 leftArg = makeNode(Var);
8112 rightArg = makeNode(Var);
8115 oe->opfuncid = opform->oprcode;
8116 oe->opresulttype = opform->oprresult;
8117 oe->opcollid = InvalidOid;
8118 oe->inputcollid = DEFAULT_COLLATION_OID;
8120 leftArg->varno = ((RangeTblRef *)setOps->larg)->rtindex;
8121 rightArg->varno = ((RangeTblRef *)setOps->rarg)->rtindex;
8122 leftArg->varattno = rightArg->varattno = attno;
8124#if PG_VERSION_NUM >= 130000
8125 leftArg->varnosyn = rightArg->varnosyn = 0;
8126 leftArg->varattnosyn = rightArg->varattnosyn = 0;
8128 leftArg->varnoold = leftArg->varno;
8129 rightArg->varnoold = rightArg->varno;
8130 leftArg->varoattno = rightArg->varoattno = attno;
8133 leftArg->vartype = rightArg->vartype = v->vartype;
8134 leftArg->varcollid = rightArg->varcollid = InvalidOid;
8135 leftArg->vartypmod = rightArg->vartypmod = -1;
8136 leftArg->location = rightArg->location = -1;
8138 oe->args = list_make2(leftArg, rightArg);
8142 expr->args = lappend(expr->args,
8143 makeBoolExpr(NOT_EXPR, list_make1(oe), -1));
8145 ReleaseSysCache(opInfo);
8159 RangeTblRef *larg_ref = (RangeTblRef *)setOps->larg;
8160 RangeTblRef *rarg_ref = (RangeTblRef *)setOps->rarg;
8161 RangeTblEntry *larg_rte =
8162 (RangeTblEntry *)list_nth(q->rtable, larg_ref->rtindex - 1);
8163 RangeTblEntry *rarg_rte =
8164 (RangeTblEntry *)list_nth(q->rtable, rarg_ref->rtindex - 1);
8165 List *aliasvars = NIL;
8166 List *leftcols = NIL;
8167 List *rightcols = NIL;
8168 List *colnames = NIL;
8173 foreach (lc_te, larg_rte->subquery->targetList) {
8174 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
8179 aliasvars = lappend(aliasvars,
8180 makeVar(larg_ref->rtindex, colno,
8181 exprType((Node *)te->expr),
8182 exprTypmod((Node *)te->expr),
8183 exprCollation((Node *)te->expr),
8185 leftcols = lappend_int(leftcols, colno);
8186 rightcols = lappend_int(rightcols, 0);
8187 colnames = lappend(colnames,
8188 makeString(pstrdup(te->resname ? te->resname
8193 foreach (lc_te, rarg_rte->subquery->targetList) {
8194 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
8199 aliasvars = lappend(aliasvars,
8200 makeVar(rarg_ref->rtindex, colno,
8201 exprType((Node *)te->expr),
8202 exprTypmod((Node *)te->expr),
8203 exprCollation((Node *)te->expr),
8205 leftcols = lappend_int(leftcols, 0);
8206 rightcols = lappend_int(rightcols, colno);
8207 colnames = lappend(colnames,
8208 makeString(pstrdup(te->resname ? te->resname
8215 rte->joinaliasvars = aliasvars;
8216#if PG_VERSION_NUM >= 130000
8217 rte->joinleftcols = leftcols;
8218 rte->joinrightcols = rightcols;
8219 rte->joinmergedcols = 0;
8226 rte->rtekind = RTE_JOIN;
8227 rte->jointype = JOIN_LEFT;
8229 q->rtable = lappend(q->rtable, rte);
8231 je->jointype = JOIN_LEFT;
8233 je->larg = setOps->larg;
8234 je->rarg = setOps->rarg;
8235 je->quals = (Node *)expr;
8236 je->rtindex = list_length(q->rtable);
8238 fe->fromlist = list_make1(je);
8244 q->setOperations = 0;
8291 foreach (lc, rel->eref->colnames) {
8293 lfirst(lc) = makeString(pstrdup(
"_provsql_inner"));
8317 if (rel->rtekind == RTE_SUBQUERY) {
8318 int cap = list_length(rel->subquery->targetList);
8319 out->
attno = (AttrNumber *)palloc(cap *
sizeof(AttrNumber));
8320 out->
type = (Oid *)palloc(cap *
sizeof(Oid));
8321 out->
typmod = (int32 *)palloc(cap *
sizeof(int32));
8322 out->
coll = (Oid *)palloc(cap *
sizeof(Oid));
8323 out->
name = (
char **)palloc(cap *
sizeof(
char *));
8325 foreach (lc, rel->subquery->targetList) {
8326 TargetEntry *te = (TargetEntry *)lfirst(lc);
8331 out->
attno[out->
n] = te->resno;
8332 out->
type[out->
n] = exprType((Node *)te->expr);
8333 out->
typmod[out->
n] = exprTypmod((Node *)te->expr);
8334 out->
coll[out->
n] = exprCollation((Node *)te->expr);
8335 out->
name[out->
n] = pstrdup(te->resname ? te->resname :
"?column?");
8342 AttrNumber attid = 0;
8343 int cap = list_length(rel->eref->colnames);
8344 out->
attno = (AttrNumber *)palloc(cap *
sizeof(AttrNumber));
8345 out->
type = (Oid *)palloc(cap *
sizeof(Oid));
8346 out->
typmod = (int32 *)palloc(cap *
sizeof(int32));
8347 out->
coll = (Oid *)palloc(cap *
sizeof(Oid));
8348 out->
name = (
char **)palloc(cap *
sizeof(
char *));
8350 foreach (lc, rel->eref->colnames) {
8351 const char *v = strVal(lfirst(lc));
8360 get_atttypetypmodcoll(rel->relid, attid, &t, &tm, &c);
8361 out->
attno[out->
n] = attid;
8362 out->
type[out->
n] = t;
8364 out->
coll[out->
n] = c;
8365 out->
name[out->
n] = pstrdup(v);
8374 RangeTblEntry *rel) {
8376 AttrNumber attid = 0;
8378 if (rel->rtekind == RTE_SUBQUERY) {
8379 if (rel->subquery == NULL)
8386 foreach (lc, rel->subquery->targetList) {
8387 TargetEntry *te = (TargetEntry *)lfirst(lc);
8388 if (!te->resjunk && te->resname &&
8396 foreach (lc, rel->eref->colnames) {
8408 RangeTblEntry *rte = makeNode(RangeTblEntry);
8409 List *colnames = NIL;
8412 foreach (lc, sub->targetList) {
8413 TargetEntry *te = (TargetEntry *)lfirst(lc);
8416 colnames = lappend(colnames,
8417 makeString(pstrdup(te->resname ? te->resname
8421 rte->rtekind = RTE_SUBQUERY;
8422 rte->subquery = sub;
8424 rte->eref = makeAlias(
"unnamed_subquery", colnames);
8425 rte->lateral =
false;
8426 rte->inFromCl =
true;
8427#if PG_VERSION_NUM < 160000
8428 rte->requiredPerms = 0;
8437 RangeTblEntry *orig) {
8438 RangeTblEntry *c = copyObject(orig);
8439#if PG_VERSION_NUM >= 160000
8440 if (orig->rtekind == RTE_RELATION && orig->perminfoindex != 0) {
8441 RTEPermissionInfo *pi = getRTEPermissionInfo(outer->rteperminfos, orig);
8442 sub->rteperminfos = lappend(sub->rteperminfos, copyObject(pi));
8443 c->perminfoindex = list_length(sub->rteperminfos);
8445 c->perminfoindex = 0;
8459 if (rel->rtekind == RTE_SUBQUERY) {
8460#if PG_VERSION_NUM >= 120000
8461 rel->rtekind = RTE_RESULT;
8462 rel->subquery = NULL;
8467 Query *empty = makeNode(Query);
8468 empty->commandType = CMD_SELECT;
8469 empty->canSetTag =
true;
8470 empty->jointree = makeFromExpr(NIL, NULL);
8471 rel->subquery = empty;
8473 rel->eref = makeAlias(
"*RESULT*", NIL);
8474#if PG_VERSION_NUM >= 160000
8475 rel->perminfoindex = 0;
8493 if (IsA(node, Var)) {
8494 Var *v = (Var *)node;
8495 if (v->varlevelsup == 0) {
8497 for (i = 0; i < c->
npairs; ++i)
8498 if (v->varno == c->
from[i]) {
8499 v = (Var *)copyObject(v);
8500 v->varno = c->
to[i];
8501#if PG_VERSION_NUM >= 160000
8502 v->varnullingrels = NULL;
8504#if PG_VERSION_NUM >= 130000
8513 return expression_tree_mutator(node,
oj_renum_mut, cx);
8524 RangeTblEntry *R, RangeTblEntry *S,
8525 Index R_idx, Index S_idx,
oj_cols *Rc,
8526 oj_cols *Sc, Node *theta,
bool select_r,
8528 Query *sub = makeNode(Query);
8529 RangeTblEntry *Rcopy, *Scopy, *jrte = makeNode(RangeTblEntry);
8530 JoinExpr *je = makeNode(JoinExpr);
8531 RangeTblRef *lr = makeNode(RangeTblRef), *rr = makeNode(RangeTblRef);
8532 FromExpr *fe = makeNode(FromExpr);
8533 List *tl = NIL, *av = NIL, *lcols = NIL, *rcols = NIL, *cn = NIL;
8538 sub->commandType = CMD_SELECT;
8539 sub->canSetTag =
true;
8545 for (i = 0; i < Rc->
n; ++i) {
8548 lcols = lappend_int(lcols, Rc->
attno[i]);
8549 rcols = lappend_int(rcols, 0);
8550 cn = lappend(cn, makeString(pstrdup(Rc->
name[i])));
8552 for (i = 0; i < Sc->
n; ++i) {
8555 lcols = lappend_int(lcols, 0);
8556 rcols = lappend_int(rcols, Sc->
attno[i]);
8557 cn = lappend(cn, makeString(pstrdup(Sc->
name[i])));
8559 jrte->rtekind = RTE_JOIN;
8560 jrte->jointype = JOIN_INNER;
8562 jrte->eref = makeAlias(
"unnamed_join", cn);
8563 jrte->joinaliasvars = av;
8564#if PG_VERSION_NUM >= 130000
8565 jrte->joinleftcols = lcols;
8566 jrte->joinrightcols = rcols;
8567 jrte->joinmergedcols = 0;
8569 jrte->inFromCl =
true;
8571 sub->rtable = list_make3(Rcopy, Scopy, jrte);
8574 rctx.
from[0] = R_idx; rctx.
to[0] = 1;
8575 rctx.
from[1] = S_idx; rctx.
to[1] = 2;
8580 je->jointype = JOIN_INNER;
8581 je->larg = (Node *)lr;
8582 je->rarg = (Node *)rr;
8584 je->isNatural =
false;
8585 je->usingClause = NIL;
8587 fe->fromlist = list_make1(je);
8591 for (i = 0; i < Rc->
n; ++i) {
8594 tl = lappend(tl, makeTargetEntry((Expr *)v, list_length(tl) + 1,
8595 pstrdup(Rc->
name[i]),
false));
8598 for (i = 0; i < Sc->
n; ++i) {
8601 tl = lappend(tl, makeTargetEntry((Expr *)v, list_length(tl) + 1,
8602 pstrdup(Sc->
name[i]),
false));
8604 sub->targetList = tl;
8611 RangeTblEntry *R,
oj_cols *Rc) {
8612 Query *sub = makeNode(Query);
8613 RangeTblEntry *Rcopy;
8614 RangeTblRef *rtr = makeNode(RangeTblRef);
8615 FromExpr *fe = makeNode(FromExpr);
8619 sub->commandType = CMD_SELECT;
8620 sub->canSetTag =
true;
8622 sub->rtable = list_make1(Rcopy);
8624 fe->fromlist = list_make1(rtr);
8627 for (i = 0; i < Rc->
n; ++i) {
8630 tl = lappend(tl, makeTargetEntry((Expr *)v, i + 1, pstrdup(Rc->
name[i]),
8633 sub->targetList = tl;
8645 RangeTblEntry *R, RangeTblEntry *S, Index R_idx,
8648 RangeTblEntry *kept_rel = keep_left ? R : S;
8649 oj_cols *Kc = keep_left ? Rc : Sc;
8653 theta, keep_left, !keep_left);
8656 Query *D = makeNode(Query);
8657 SetOperationStmt *so = makeNode(SetOperationStmt);
8658 RangeTblRef *l = makeNode(RangeTblRef), *r = makeNode(RangeTblRef);
8659 FromExpr *fe = makeNode(FromExpr);
8663 D->commandType = CMD_SELECT;
8664 D->canSetTag =
true;
8665 D->rtable = list_make2(ls_rte, mp_rte);
8669 so->op = SETOP_EXCEPT;
8675 so->larg = (Node *)l;
8676 so->rarg = (Node *)r;
8677 for (i = 0; i < Kc->
n; ++i) {
8678 so->colTypes = lappend_oid(so->colTypes, Kc->
type[i]);
8679 so->colTypmods = lappend_int(so->colTypmods, Kc->
typmod[i]);
8680 so->colCollations = lappend_oid(so->colCollations, Kc->
coll[i]);
8682 D->setOperations = (Node *)so;
8686 for (i = 0; i < Kc->
n; ++i) {
8687 Var *v = makeVar(1, i + 1, Kc->
type[i], Kc->
typmod[i], Kc->
coll[i], 0);
8688 tl = lappend(tl, makeTargetEntry((Expr *)v, i + 1, pstrdup(Kc->
name[i]),
8704 RangeTblEntry *R, RangeTblEntry *S,
8705 Index R_idx, Index S_idx,
oj_cols *Rc,
8706 oj_cols *Sc, Node *theta,
bool keep_left) {
8707 Query *D =
oj_build_diff(constants, outer, R, S, R_idx, S_idx, Rc, Sc, theta,
8710 Query *A = makeNode(Query);
8711 RangeTblRef *rtr = makeNode(RangeTblRef);
8712 FromExpr *fe = makeNode(FromExpr);
8716 A->commandType = CMD_SELECT;
8717 A->canSetTag =
true;
8718 A->rtable = list_make1(D_rte);
8720 fe->fromlist = list_make1(rtr);
8724 for (i = 0; i < Rc->
n; ++i) {
8727 e = (Expr *)makeVar(1, ++kept, Rc->
type[i], Rc->
typmod[i], Rc->
coll[i],
8730 e = (Expr *)makeNullConst(Rc->
type[i], Rc->
typmod[i], Rc->
coll[i]);
8731 tl = lappend(tl, makeTargetEntry(e, list_length(tl) + 1,
8732 pstrdup(Rc->
name[i]),
false));
8735 for (i = 0; i < Sc->
n; ++i) {
8738 e = (Expr *)makeNullConst(Sc->
type[i], Sc->
typmod[i], Sc->
coll[i]);
8740 e = (Expr *)makeVar(1, ++kept, Sc->
type[i], Sc->
typmod[i], Sc->
coll[i],
8742 tl = lappend(tl, makeTargetEntry(e, list_length(tl) + 1,
8743 pstrdup(Sc->
name[i]),
false));
8752 List **typmods, List **collations) {
8754 *types = *typmods = *collations = NIL;
8755 for (i = 0; i < Rc->
n; ++i) {
8756 *types = lappend_oid(*types, Rc->
type[i]);
8757 *typmods = lappend_int(*typmods, Rc->
typmod[i]);
8758 *collations = lappend_oid(*collations, Rc->
coll[i]);
8760 for (i = 0; i < Sc->
n; ++i) {
8761 *types = lappend_oid(*types, Sc->
type[i]);
8762 *typmods = lappend_int(*typmods, Sc->
typmod[i]);
8763 *collations = lappend_oid(*collations, Sc->
coll[i]);
8775 RangeTblEntry *R, RangeTblEntry *S, Index R_idx,
8777 JoinType jointype) {
8779 List *types, *typmods, *collations;
8780 Query *Q = makeNode(Query);
8781 FromExpr *fe = makeNode(FromExpr);
8789 S_idx, Rc, Sc, theta,
true,
true));
8790 if (jointype == JOIN_LEFT || jointype == JOIN_FULL)
8792 S_idx, Rc, Sc, theta,
true));
8793 if (jointype == JOIN_RIGHT || jointype == JOIN_FULL)
8795 S_idx, Rc, Sc, theta,
false));
8797 Q->commandType = CMD_SELECT;
8798 Q->canSetTag =
true;
8808 RangeTblRef *first = makeNode(RangeTblRef);
8810 tree = (Node *)first;
8812 for (k = 2; k <= list_length(arms); ++k) {
8813 SetOperationStmt *so = makeNode(SetOperationStmt);
8814 RangeTblRef *rtr = makeNode(RangeTblRef);
8816 so->op = SETOP_UNION;
8819 so->rarg = (Node *)rtr;
8820 so->colTypes = list_copy(types);
8821 so->colTypmods = list_copy(typmods);
8822 so->colCollations = list_copy(collations);
8825 Q->setOperations = tree;
8830 for (i = 0; i < Rc->
n; ++i) {
8831 Var *v = makeVar(1, ++pos, Rc->
type[i], Rc->
typmod[i], Rc->
coll[i], 0);
8832 tl = lappend(tl, makeTargetEntry((Expr *)v, pos, pstrdup(Rc->
name[i]),
8835 for (i = 0; i < Sc->
n; ++i) {
8836 Var *v = makeVar(1, ++pos, Sc->
type[i], Sc->
typmod[i], Sc->
coll[i], 0);
8837 tl = lappend(tl, makeTargetEntry((Expr *)v, pos, pstrdup(Sc->
name[i]),
8853 if (IsA(node, Var)) {
8854 Var *v = (Var *)node;
8855 return (v->varlevelsup == 0 && v->varno == c->
join_idx);
8868 if (q->jointree && q->jointree->quals &&
8888 if (IsA(node, Var)) {
8889 Var *v = (Var *)node;
8890 if (v->varlevelsup == 0 &&
8891 (v->varno == c->
R_idx || v->varno == c->
S_idx)) {
8892 v = (Var *)copyObject(v);
8893 if ((Index)((Var *)node)->varno == c->
R_idx)
8894 v->varattno = c->
R_map[v->varattno];
8896 v->varattno = c->
S_map[v->varattno];
8898#if PG_VERSION_NUM >= 160000
8899 v->varnullingrels = NULL;
8901#if PG_VERSION_NUM >= 130000
8927 if (IsA(n, RangeTblRef)) {
8928 RangeTblEntry *rte = rt_fetch(((RangeTblRef *)n)->rtindex, q->rtable);
8930 if (rte->rtekind == RTE_RELATION || rte->rtekind == RTE_SUBQUERY)
8932 foreach (lc, rte->eref->colnames) {
8938 if (IsA(n, JoinExpr))
8941 if (IsA(n, FromExpr)) {
8943 foreach (lc, ((FromExpr *)n)->fromlist)
8971 if (IsA(n, FromExpr)) {
8973 foreach (lc, ((FromExpr *)n)->fromlist)
8977 if (!IsA(n, JoinExpr))
8984 if (je->jointype != JOIN_LEFT && je->jointype != JOIN_RIGHT &&
8985 je->jointype != JOIN_FULL)
8988 if (je->rtindex > 0) {
8989 RangeTblEntry *jrte = rt_fetch(je->rtindex, q->rtable);
8990 if (jrte->eref && jrte->eref->aliasname &&
8995 if (((je->jointype == JOIN_LEFT || je->jointype == JOIN_FULL) &&
8997 ((je->jointype == JOIN_RIGHT || je->jointype == JOIN_FULL) &&
9000 "unsupported %s JOIN: a provenance-tracked relation sits on the "
9001 "null-padded side of a join that could not be lowered (only a "
9002 "two-relation outer join with no outer reference to the join RTE "
9003 "is); rewrite the query or remove provenance from the null-padded "
9005 je->jointype == JOIN_LEFT ?
"LEFT"
9006 : je->jointype == JOIN_RIGHT ?
"RIGHT" :
"FULL");
9021 RangeTblRef *lref, *rref;
9022 Index R_idx, S_idx, join_idx;
9023 RangeTblEntry *R_rte, *S_rte;
9027 AttrNumber *R_map, *S_map;
9028 int ncolR, ncolS, i;
9031 if (q->commandType != CMD_SELECT)
9033 if (!q->jointree || list_length(q->jointree->fromlist) != 1)
9035 if (!IsA(linitial(q->jointree->fromlist), JoinExpr))
9037 je = (JoinExpr *)linitial(q->jointree->fromlist);
9038 if (je->jointype != JOIN_LEFT && je->jointype != JOIN_RIGHT &&
9039 je->jointype != JOIN_FULL)
9041 if (!IsA(je->larg, RangeTblRef) || !IsA(je->rarg, RangeTblRef))
9044 lref = (RangeTblRef *)je->larg;
9045 rref = (RangeTblRef *)je->rarg;
9046 R_idx = lref->rtindex;
9047 S_idx = rref->rtindex;
9048 join_idx = je->rtindex;
9049 R_rte = list_nth_node(RangeTblEntry, q->rtable, R_idx - 1);
9050 S_rte = list_nth_node(RangeTblEntry, q->rtable, S_idx - 1);
9052 if ((R_rte->rtekind != RTE_RELATION && R_rte->rtekind != RTE_SUBQUERY) ||
9053 (S_rte->rtekind != RTE_RELATION && S_rte->rtekind != RTE_SUBQUERY))
9055 if ((R_rte->rtekind == RTE_SUBQUERY && R_rte->lateral) ||
9056 (S_rte->rtekind == RTE_SUBQUERY && S_rte->lateral))
9064#if PG_VERSION_NUM >= 180000
9073 ncolR = (R_rte->rtekind == RTE_SUBQUERY)
9074 ? list_length(R_rte->subquery->targetList)
9075 : list_length(R_rte->eref->colnames);
9076 ncolS = (S_rte->rtekind == RTE_SUBQUERY)
9077 ? list_length(S_rte->subquery->targetList)
9078 : list_length(S_rte->eref->colnames);
9080 Q =
oj_build_union(constants, q, R_rte, S_rte, R_idx, S_idx, &Rc, &Sc, theta,
9089 R_map = (AttrNumber *)palloc0((ncolR + 1) *
sizeof(AttrNumber));
9090 S_map = (AttrNumber *)palloc0((ncolS + 1) *
sizeof(AttrNumber));
9091 for (i = 0; i < Rc.
n; ++i)
9092 R_map[Rc.
attno[i]] = i + 1;
9093 for (i = 0; i < Sc.
n; ++i)
9094 S_map[Sc.
attno[i]] = Rc.
n + i + 1;
9103 RangeTblEntry *J_rte =
9104 list_nth_node(RangeTblEntry, q->rtable, join_idx - 1);
9107 J_rte->rtekind = RTE_SUBQUERY;
9108 J_rte->subquery = Q;
9109 J_rte->jointype = JOIN_INNER;
9110 J_rte->joinaliasvars = NIL;
9111#if PG_VERSION_NUM >= 130000
9112 J_rte->joinleftcols = NIL;
9113 J_rte->joinrightcols = NIL;
9114 J_rte->joinmergedcols = 0;
9116 J_rte->relid = InvalidOid;
9118#if PG_VERSION_NUM >= 120000
9119 J_rte->rellockmode = 0;
9122 J_rte->lateral =
false;
9123 J_rte->tablesample = NULL;
9124#if PG_VERSION_NUM >= 160000
9125 J_rte->perminfoindex = 0;
9127 J_rte->selectedCols = NULL;
9128 J_rte->insertedCols = NULL;
9129 J_rte->updatedCols = NULL;
9130 J_rte->requiredPerms = ACL_SELECT;
9132 for (i = 0; i < Rc.
n; ++i)
9133 cn = lappend(cn, makeString(pstrdup(Rc.
name[i])));
9134 for (i = 0; i < Sc.
n; ++i)
9135 cn = lappend(cn, makeString(pstrdup(Sc.
name[i])));
9136 J_rte->eref = makeAlias(
"unnamed_subquery", cn);
9140 RangeTblRef *newr = makeNode(RangeTblRef);
9141 newr->rtindex = join_idx;
9142 q->jointree->fromlist = list_make1(newr);
9150 q->targetList = (List *)
oj_outer_remap((Node *)q->targetList, &octx);
9151 if (q->jointree->quals)
9190 if (IsA(node, Var)) {
9191 Var *v = (Var *)node;
9192 if (v->varlevelsup == 1) {
9193 v = (Var *)copyObject(v);
9197 if (v->varlevelsup == 0 && v->varno == c->
q_old) {
9198 v = (Var *)copyObject(v);
9199 v->varno = c->
q_new;
9200#if PG_VERSION_NUM >= 130000
9230 if (IsA(node, Var)) {
9231 Var *v = (Var *)node;
9232 if (s->
found_var == NULL && v->varlevelsup == 0 &&
9250 if (node == (Node *)c->
target)
9259 if (node == (Node *)cx)
9267 Aggref *agg = makeNode(Aggref);
9268 TargetEntry *te = makeNode(TargetEntry);
9271 agg->aggfnoid = aggfnoid;
9272 agg->aggtype = aggtype;
9273 agg->aggtranstype = InvalidOid;
9274 agg->aggargtypes = list_make1_oid(argtype);
9275 agg->args = list_make1(te);
9276 agg->aggkind = AGGKIND_NORMAL;
9277 agg->aggsplit = AGGSPLIT_SIMPLE;
9279#if PG_VERSION_NUM >= 140000
9280 agg->aggno = agg->aggtransno = -1;
9295 Var *qkey = (Var *)copyObject((Node *)found_var);
9297 OpExpr *op = makeNode(OpExpr);
9300 qkey->varno = q_idx;
9301#if PG_VERSION_NUM >= 130000
9303 qkey->varattnosyn = 0;
9307 o = OpernameGetOprid(list_make1(makeString((
char *)opstr)), INT8OID, INT8OID);
9309 op->opfuncid = get_opcode(o);
9310 op->opresulttype = BOOLOID;
9311 op->opcollid = InvalidOid;
9312 op->inputcollid = InvalidOid;
9313 op->args = list_make2(cnt, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
9314 Int64GetDatum(n),
false, FLOAT8PASSBYVAL));
9324 Aggref *cnt = makeNode(Aggref);
9325 TargetEntry *arg = makeTargetEntry((Expr *)copyObject((Node *)valexpr), 1,
9327 SortGroupClause *sgc = makeNode(SortGroupClause);
9328 OpExpr *op = makeNode(OpExpr);
9331 arg->ressortgroupref = 1;
9332 sgc->tleSortGroupRef = 1;
9333 get_sort_group_operators(exprType((Node *)valexpr),
false,
true,
false,
9334 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
9337 cnt->aggtype = INT8OID;
9338 cnt->aggtranstype = InvalidOid;
9339 cnt->aggargtypes = list_make1_oid(exprType((Node *)valexpr));
9340 cnt->args = list_make1(arg);
9341 cnt->aggdistinct = list_make1(sgc);
9342 cnt->aggkind = AGGKIND_NORMAL;
9343 cnt->aggsplit = AGGSPLIT_SIMPLE;
9345#if PG_VERSION_NUM >= 140000
9346 cnt->aggno = cnt->aggtransno = -1;
9349 o = OpernameGetOprid(list_make1(makeString((
char *)opstr)), INT8OID, INT8OID);
9351 op->opfuncid = get_opcode(o);
9352 op->opresulttype = BOOLOID;
9353 op->opcollid = InvalidOid;
9354 op->inputcollid = InvalidOid;
9355 op->args = list_make2(cnt, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
9356 Int64GetDatum(n),
false, FLOAT8PASSBYVAL));
9377 if (c->
skip && node == (Node *)c->
skip)
9379 if (IsA(node, Var)) {
9380 Var *v = (Var *)node;
9381 if ((
int)v->varlevelsup == c->
target_level && (
int)v->varno >= 1 &&
9382 (
int)v->varno <= c->
rtlen && c->
pos[v->varno] != NULL &&
9383 v->varattno >= 1 && c->
pos[v->varno][v->varattno] > 0) {
9384 Var *nv = (Var *)copyObject(v);
9386 nv->varattno = c->
pos[v->varno][v->varattno];
9387#if PG_VERSION_NUM >= 130000
9389 nv->varattnosyn = 0;
9411 SubLink *sl,
bool in_where) {
9412 int rtlen = list_length(q->rtable);
9413 int **pos = (
int **)palloc0((rtlen + 1) *
sizeof(
int *));
9414 Query *Rp = makeNode(Query);
9415 RangeTblEntry *rp_rte;
9416 RangeTblRef *rtr = makeNode(RangeTblRef);
9417 FromExpr *outer_fe = makeNode(FromExpr);
9419 Node *subquery_conj = NULL;
9420 List *kept_conj = NIL;
9424 bool any_tracked =
false;
9428 foreach (lc, q->rtable) {
9429 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
9431 if (r->rtekind == RTE_RELATION) {
9434 }
else if (r->rtekind != RTE_JOIN) {
9441 foreach (lc, q->rtable) {
9442 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
9446 if (r->rtekind != RTE_RELATION)
9449 pos[idx] = (
int *)palloc0((list_length(r->eref->colnames) + 1) *
sizeof(
int));
9450 for (j = 0; j < rc.
n; ++j) {
9452 rp_tl = lappend(rp_tl, makeTargetEntry((Expr *)v, ++posn,
9453 pstrdup(rc.
name[j]),
false));
9454 pos[idx][rc.
attno[j]] = posn;
9464 FuncExpr *one = makeNode(FuncExpr);
9469 rp_tl = lappend(rp_tl, makeTargetEntry((Expr *)one, ++posn,
9475 if (q->jointree->quals) {
9476 Node *quals = q->jointree->quals;
9477 List *conjs = (IsA(quals, BoolExpr) &&
9478 ((BoolExpr *)quals)->boolop == AND_EXPR)
9479 ? ((BoolExpr *)quals)->args
9480 : list_make1(quals);
9481 foreach (lc, conjs) {
9482 Node *cnode = (Node *)lfirst(lc);
9484 subquery_conj = cnode;
9486 kept_conj = lappend(kept_conj, cnode);
9491 Rp->commandType = CMD_SELECT;
9492 Rp->canSetTag =
true;
9493 Rp->rtable = q->rtable;
9494 Rp->jointree = makeNode(FromExpr);
9495 Rp->jointree->fromlist = q->jointree->fromlist;
9496 Rp->jointree->quals =
9499 : (list_length(kept_conj) == 1 ? (Node *)linitial(kept_conj)
9500 : (Node *)makeBoolExpr(AND_EXPR, kept_conj,
9502 Rp->targetList = rp_tl;
9503#if PG_VERSION_NUM >= 160000
9504 Rp->rteperminfos = q->rteperminfos;
9524 Query *sub = (Query *)sl->subselect;
9528 if (sub->jointree && sub->jointree->quals)
9534 q->rtable = list_make1(rp_rte);
9535#if PG_VERSION_NUM >= 160000
9536 q->rteperminfos = NIL;
9539 outer_fe->fromlist = list_make1(rtr);
9540 outer_fe->quals = subquery_conj;
9541 q->jointree = outer_fe;
9565 bool corr_supplied) {
9567 if (!IsA(sub, Query) || sub->commandType != CMD_SELECT)
9569 if (sub->groupClause || sub->groupingSets || sub->hasAggs ||
9570 sub->distinctClause || sub->setOperations || sub->hasWindowFuncs ||
9571 sub->hasSubLinks || sub->limitCount || sub->limitOffset || sub->cteList ||
9574 if (!sub->jointree || (!corr_supplied && !sub->jointree->quals))
9580 bool any_tracked =
false;
9581 foreach (lc, sub->rtable) {
9582 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
9583 if (r->rtekind != RTE_RELATION)
9591 foreach (lc, sub->jointree->fromlist) {
9592 if (!IsA(lfirst(lc), RangeTblRef))
9617 Query *sq = (Query *)copyObject(subselect);
9618 Aggref *cnt = makeNode(Aggref);
9619 SubLink *sl = makeNode(SubLink);
9620 OpExpr *op = makeNode(OpExpr);
9624 sq->jointree->quals =
9626 ? (Node *)makeBoolExpr(AND_EXPR,
9627 list_make2(sq->jointree->quals, extra_corr), -1)
9631 cnt->aggtype = INT8OID;
9632 cnt->aggtranstype = InvalidOid;
9633 cnt->aggargtypes = NIL;
9635 cnt->aggstar =
true;
9636 cnt->aggkind = AGGKIND_NORMAL;
9637 cnt->aggsplit = AGGSPLIT_SIMPLE;
9639#if PG_VERSION_NUM >= 140000
9640 cnt->aggno = cnt->aggtransno = -1;
9643 list_make1(makeTargetEntry((Expr *)cnt, 1, pstrdup(
"count"),
false));
9646 sl->subLinkType = EXPR_SUBLINK;
9647 sl->subselect = (Node *)sq;
9648 sl->testexpr = NULL;
9652 o = OpernameGetOprid(list_make1(makeString(antijoin ?
"=" :
">=")), INT8OID,
9655 op->opfuncid = get_opcode(o);
9656 op->opresulttype = BOOLOID;
9657 op->opcollid = InvalidOid;
9658 op->inputcollid = InvalidOid;
9659 op->args = list_make2(sl, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
9660 Int64GetDatum(antijoin ? 0 : 1),
false,
9677 if (IsA(node, Param)) {
9678 Param *p = (Param *)node;
9679 if (p->paramkind == PARAM_SUBLINK && p->paramid == c->
paramid)
9692 foreach (lc, body->rtable) {
9693 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
9694 if ((r->rtekind == RTE_RELATION || r->rtekind == RTE_SUBQUERY) &&
9720 List *conjs, *newconjs = NIL;
9722 bool changed =
false;
9724 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
9725 !q->jointree->quals)
9728 quals = q->jointree->quals;
9729 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
9730 ? ((BoolExpr *)quals)->args
9731 : list_make1(quals);
9733 foreach (lc, conjs) {
9734 Node *c = (Node *)lfirst(lc);
9735 Node *inner = c, *rewritten = NULL;
9738 if (IsA(c, BoolExpr) && ((BoolExpr *)c)->boolop == NOT_EXPR &&
9739 list_length(((BoolExpr *)c)->args) == 1) {
9741 inner = (Node *)linitial(((BoolExpr *)c)->args);
9743 if (IsA(inner, SubLink) &&
9744 (((SubLink *)inner)->subLinkType == ANY_SUBLINK ||
9745 ((SubLink *)inner)->subLinkType == ALL_SUBLINK) &&
9746 IsA(((SubLink *)inner)->subselect, Query)) {
9747 SubLink *sl = (SubLink *)inner;
9748 Query *body = (Query *)sl->subselect;
9749 if (body->commandType == CMD_SELECT && body->hasAggs &&
9750 !body->groupClause && !body->groupingSets && !body->setOperations &&
9751 !body->hasWindowFuncs && !body->hasSubLinks && !body->limitCount &&
9752 !body->limitOffset && !body->cteList &&
9753 list_length(body->targetList) == 1 &&
9754 IsA(((TargetEntry *)linitial(body->targetList))->expr, Aggref) &&
9755 sl->testexpr && IsA(sl->testexpr, OpExpr) &&
9756 list_length(((OpExpr *)sl->testexpr)->args) == 2 &&
9758 OpExpr *op = (OpExpr *)copyObject(sl->testexpr);
9759 Oid opno = neg ? get_negator(op->opno) : op->opno;
9760 if (OidIsValid(opno)) {
9761 SubLink *esl = makeNode(SubLink);
9763 esl->subLinkType = EXPR_SUBLINK;
9764 esl->testexpr = NULL;
9765 esl->operName = NIL;
9766 esl->subselect = (Node *)copyObject(body);
9769 op->opfuncid = get_opcode(opno);
9776 newconjs = lappend(newconjs, rewritten ? rewritten : c);
9782 q->jointree->quals = (list_length(newconjs) == 1)
9783 ? (Node *)linitial(newconjs)
9784 : (Node *)makeBoolExpr(AND_EXPR, newconjs, -1);
9799 while (e && IsA(e, RelabelType))
9800 e = (Node *)((RelabelType *)e)->arg;
9804 return !((Const *)e)->constisnull;
9806 const Var *v = (
const Var *)e;
9810 if (v->varlevelsup != levelsup || v->varattno <= 0 ||
9811 v->varno <= 0 || (
int)v->varno > list_length(q->rtable))
9813 rte = rt_fetch(v->varno, q->rtable);
9814 if (rte->rtekind != RTE_RELATION)
9816 atttup = SearchSysCache2(ATTNUM, ObjectIdGetDatum(rte->relid),
9817 Int16GetDatum(v->varattno));
9818 if (!HeapTupleIsValid(atttup))
9820 notnull = ((Form_pg_attribute) GETSTRUCT(atttup))->attnotnull;
9821 ReleaseSysCache(atttup);
9856 const Query *outerq,
bool *guarded) {
9857 Query *sub = (Query *)sl->subselect;
9858 List *opexprs, *conjs = NIL;
9868 if (sl->subLinkType == ANY_SUBLINK) {
9871 }
else if (sl->subLinkType == ALL_SUBLINK) {
9879 null_guards = *antijoin ^ neg;
9883 if (IsA(sl->testexpr, OpExpr))
9884 opexprs = list_make1(sl->testexpr);
9885 else if (sl->subLinkType == ANY_SUBLINK && IsA(sl->testexpr, BoolExpr) &&
9886 ((BoolExpr *)sl->testexpr)->boolop == AND_EXPR)
9887 opexprs = ((BoolExpr *)sl->testexpr)->args;
9891 foreach (lc, opexprs) {
9892 OpExpr *oe = (OpExpr *)lfirst(lc);
9893 Node *rhs, *qcol, *ci;
9897 if (!IsA(oe, OpExpr) || list_length(oe->args) != 2)
9899 rhs = (Node *)lsecond(oe->args);
9900 if (IsA(rhs, RelabelType))
9901 rhs = (Node *)((RelabelType *)rhs)->arg;
9902 if (!IsA(rhs, Param))
9905 if (p->paramkind != PARAM_SUBLINK || p->paramid < 1 ||
9906 p->paramid > list_length(sub->targetList))
9912 ci = copyObject((Node *)oe);
9914 Oid negop = get_negator(((OpExpr *)ci)->opno);
9915 if (!OidIsValid(negop))
9917 ((OpExpr *)ci)->opno = negop;
9918 ((OpExpr *)ci)->opfuncid = get_opcode(negop);
9920 IncrementVarSublevelsUp(ci, 1, 0);
9922 (Node *)((TargetEntry *)list_nth(sub->targetList, p->paramid - 1))->expr);
9931 List *disj = list_make1(ci);
9936 NullTest *nx = makeNode(NullTest);
9937 nx->arg = (Expr *)copyObject(linitial(((OpExpr *)ci)->args));
9938 nx->nulltesttype = IS_NULL;
9939 nx->argisrow =
false;
9941 disj = lappend(disj, nx);
9944 NullTest *nq = makeNode(NullTest);
9945 nq->arg = (Expr *)copyObject(qcol);
9946 nq->nulltesttype = IS_NULL;
9947 nq->argisrow =
false;
9949 disj = lappend(disj, nq);
9951 if (list_length(disj) > 1) {
9952 ci = (Node *)makeBoolExpr(OR_EXPR, disj, -1);
9956 conjs = lappend(conjs, ci);
9961 return (list_length(conjs) == 1)
9962 ? (Node *)linitial(conjs)
9963 : (Node *)makeBoolExpr(AND_EXPR, conjs, -1);
9983 List *conjs, *newconjs = NIL;
9985 bool changed =
false;
9987 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
9988 !q->jointree->quals)
9991 quals = q->jointree->quals;
9992 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
9993 ? ((BoolExpr *)quals)->args
9994 : list_make1(quals);
9996 foreach (lc, conjs) {
9997 Node *c = (Node *)lfirst(lc);
9998 Node *inner = c, *rewritten = NULL;
10002 if (IsA(c, BoolExpr) && ((BoolExpr *)c)->boolop == NOT_EXPR &&
10003 list_length(((BoolExpr *)c)->args) == 1) {
10005 inner = (Node *)linitial(((BoolExpr *)c)->args);
10007 if (IsA(inner, SubLink) && IsA(((SubLink *)inner)->subselect, Query)) {
10008 sl = (SubLink *)inner;
10009 if (sl->subLinkType == EXISTS_SUBLINK &&
10011 (Query *)sl->subselect,
false)) {
10015 }
else if (sl->subLinkType == ANY_SUBLINK ||
10016 sl->subLinkType == ALL_SUBLINK) {
10019 bool base_antijoin;
10020 bool guarded =
false;
10025 (Query *)sl->subselect,
true)) {
10031 (Query *)sl->subselect))
10039 base_antijoin ^ neg);
10043 newconjs = lappend(newconjs, rewritten ? rewritten : c);
10049 q->jointree->quals = (list_length(newconjs) == 1)
10050 ? (Node *)linitial(newconjs)
10051 : (Node *)makeBoolExpr(AND_EXPR, newconjs, -1);
10069 bool changed =
false;
10071 if (q->commandType != CMD_SELECT || !q->hasSubLinks)
10074 foreach (lc, q->targetList) {
10075 TargetEntry *te = (TargetEntry *)lfirst(lc);
10078 TargetEntry *innerte;
10079 Oid elemtype, arrtype;
10084 if (!IsA(te->expr, SubLink))
10086 sl = (SubLink *)te->expr;
10087 if (sl->subLinkType != ARRAY_SUBLINK || !IsA(sl->subselect, Query))
10089 sub = (Query *)sl->subselect;
10098 foreach (tlc, sub->targetList)
10099 if (!((TargetEntry *)lfirst(tlc))->resjunk)
10101 if (nreal != 1 || ((TargetEntry *)linitial(sub->targetList))->resjunk)
10105 innerte = (TargetEntry *)linitial(sub->targetList);
10106 elemtype = exprType((Node *)innerte->expr);
10107 arrtype = get_array_type(elemtype);
10108 if (!OidIsValid(arrtype))
10120 if (sub->sortClause) {
10128 List *args = NIL, *argtypes = NIL;
10130 agg = makeNode(Aggref);
10131 foreach (alc, sub->targetList) {
10132 TargetEntry *ate = (TargetEntry *)copyObject(lfirst(alc));
10133 args = lappend(args, ate);
10134 argtypes = lappend_oid(argtypes, exprType((Node *)ate->expr));
10137 agg->aggtype = arrtype;
10138 agg->aggtranstype = InvalidOid;
10139 agg->aggargtypes = argtypes;
10141 agg->aggorder = (List *)copyObject((Node *)sub->sortClause);
10142 agg->aggkind = AGGKIND_NORMAL;
10143 agg->aggsplit = AGGSPLIT_SIMPLE;
10144 agg->location = -1;
10145#if PG_VERSION_NUM >= 140000
10146 agg->aggno = agg->aggtransno = -1;
10157 nt = makeNode(NullTest);
10158 nt->arg = (Expr *)copyObject((Node *)scan.
found_var);
10159 nt->nulltesttype = IS_NOT_NULL;
10160 nt->argisrow =
false;
10162 agg->aggfilter = (Expr *)nt;
10167 sub->targetList = list_make1(makeTargetEntry(
10168 (Expr *)agg, 1, innerte->resname ? pstrdup(innerte->resname) : NULL,
10170 sub->sortClause = NIL;
10171 sub->hasAggs =
true;
10172 sl->subLinkType = EXPR_SUBLINK;
10195 int rtlen = list_length(sub->rtable);
10197 Query *D = makeNode(Query);
10198 RangeTblEntry *d_rte;
10199 RangeTblRef *rtr = makeNode(RangeTblRef);
10205 if (!sub->jointree || sub->jointree->fromlist == NIL)
10208 bool any_tracked =
false;
10209 foreach (lc, sub->rtable) {
10210 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
10211 if (r->rtekind != RTE_RELATION)
10214 any_tracked =
true;
10219 foreach (lc, sub->jointree->fromlist) {
10220 if (!IsA(lfirst(lc), RangeTblRef))
10225 pos = (
int **)palloc0((rtlen + 1) *
sizeof(
int *));
10227 foreach (lc, sub->rtable) {
10228 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
10234 (
int *)palloc0((list_length(r->eref->colnames) + 1) *
sizeof(
int));
10235 for (j = 0; j < rc.
n; ++j) {
10238 d_tl = lappend(d_tl, makeTargetEntry((Expr *)v, ++posn,
10239 pstrdup(rc.
name[j]),
false));
10240 pos[idx][rc.
attno[j]] = posn;
10245 D->commandType = CMD_SELECT;
10246 D->canSetTag =
true;
10247 D->rtable = sub->rtable;
10248 D->jointree = makeNode(FromExpr);
10249 D->jointree->fromlist = sub->jointree->fromlist;
10250 D->jointree->quals = NULL;
10251 D->targetList = d_tl;
10252#if PG_VERSION_NUM >= 160000
10253 D->rteperminfos = sub->rteperminfos;
10263 if (sub->jointree->quals)
10268 sub->rtable = list_make1(d_rte);
10269#if PG_VERSION_NUM >= 160000
10270 sub->rteperminfos = NIL;
10273 sub->jointree->fromlist = list_make1(rtr);
10279#define PROVSQL_MATCH_IND_COLNAME "provsql_match_ind"
10295 RangeTblEntry *d_rte;
10301 d_rte = (RangeTblEntry *)linitial(sub->rtable);
10302 D = d_rte->subquery;
10303 D->targetList = lappend(
10305 makeTargetEntry((Expr *)makeBoolConst(
true,
false),
10306 list_length(D->targetList) + 1,
10308 d_rte->eref->colnames = lappend(
10334 if (!IsA(body, Query) || body->commandType != CMD_SELECT)
10336 if (body->groupClause || body->groupingSets || body->distinctClause ||
10337 body->setOperations || body->hasWindowFuncs || body->hasSubLinks ||
10338 body->limitCount || body->limitOffset || body->cteList ||
10339 list_length(body->targetList) != 1)
10341 if (!body->jointree || body->jointree->fromlist == NIL)
10344 if (contain_vars_of_level((Node *)body->targetList, 1) ||
10345 (body->jointree->quals && contain_vars_of_level(body->jointree->quals, 1)))
10349 foreach (lc, body->rtable) {
10350 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
10354 foreach (lc, body->jointree->fromlist) {
10355 if (!IsA(lfirst(lc), RangeTblRef))
10359 vte = (TargetEntry *)linitial(body->targetList);
10361 if (body->hasAggs) {
10363 if (!IsA(vte->expr, Aggref))
10365 D = (Query *)copyObject(body);
10375 D = (Query *)copyObject(body);
10376 vte = (TargetEntry *)linitial(D->targetList);
10378 exprType((Node *)vte->expr),
10379 exprType((Node *)vte->expr), vte->expr);
10382 cnt = makeNode(Aggref);
10384 cnt->aggtype = INT8OID;
10385 cnt->aggtranstype = InvalidOid;
10386 cnt->aggargtypes = NIL;
10388 cnt->aggstar =
true;
10389 cnt->aggkind = AGGKIND_NORMAL;
10390 cnt->aggsplit = AGGSPLIT_SIMPLE;
10391 cnt->location = -1;
10392#if PG_VERSION_NUM >= 140000
10393 cnt->aggno = cnt->aggtransno = -1;
10395 le = makeNode(OpExpr);
10396 le_op = OpernameGetOprid(list_make1(makeString(
"<=")), INT8OID, INT8OID);
10398 le->opfuncid = get_opcode(le_op);
10399 le->opresulttype = BOOLOID;
10400 le->opcollid = InvalidOid;
10401 le->inputcollid = InvalidOid;
10402 le->args = list_make2(cnt, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
10403 Int64GetDatum(1),
false,
10406 D->havingQual = (Node *)le;
10416 if (!IsA(sub, Query) || sub->commandType != CMD_SELECT)
10418 if (sub->groupClause || sub->groupingSets || sub->distinctClause ||
10419 sub->setOperations || sub->hasWindowFuncs || sub->hasSubLinks ||
10420 sub->limitCount || sub->limitOffset || sub->cteList)
10422 if (!sub->jointree || sub->jointree->fromlist == NIL)
10424 if (contain_vars_of_level((Node *)sub->targetList, 1) ||
10425 (sub->jointree->quals && contain_vars_of_level(sub->jointree->quals, 1)))
10427 foreach (lc, sub->rtable) {
10428 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
10432 foreach (lc, sub->jointree->fromlist) {
10433 if (!IsA(lfirst(lc), RangeTblRef))
10441 Aggref *cnt = makeNode(Aggref);
10443 cnt->aggtype = INT8OID;
10444 cnt->aggtranstype = InvalidOid;
10445 cnt->aggargtypes = NIL;
10447 cnt->aggstar =
true;
10448 cnt->aggkind = AGGKIND_NORMAL;
10449 cnt->aggsplit = AGGSPLIT_SIMPLE;
10450 cnt->location = -1;
10451#if PG_VERSION_NUM >= 140000
10452 cnt->aggno = cnt->aggtransno = -1;
10461 Query *D = (Query *)copyObject(body);
10462 D->targetList = list_make1(makeTargetEntry(
10463 (Expr *)makeConst(INT4OID, -1, InvalidOid,
sizeof(int32), Int32GetDatum(1),
10465 1, pstrdup(
"exists"),
false));
10466 D->havingQual = pred;
10487 List *conjs, *newconjs = NIL;
10489 bool changed =
false;
10491 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
10492 !q->jointree->quals)
10495 quals = q->jointree->quals;
10496 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
10497 ? ((BoolExpr *)quals)->args
10498 : list_make1(quals);
10500 foreach (lc, conjs) {
10501 Node *c = (Node *)lfirst(lc);
10504 if (IsA(c, SubLink) && ((SubLink *)c)->subLinkType == EXISTS_SUBLINK &&
10505 IsA(((SubLink *)c)->subselect, Query) &&
10507 (Query *)((SubLink *)c)->subselect)) {
10509 OpExpr *ge = makeNode(OpExpr);
10510 Oid o = OpernameGetOprid(list_make1(makeString(
">=")), INT8OID, INT8OID);
10512 ge->opfuncid = get_opcode(o);
10513 ge->opresulttype = BOOLOID;
10514 ge->opcollid = InvalidOid;
10515 ge->inputcollid = InvalidOid;
10517 makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
10518 Int64GetDatum(1),
false, FLOAT8PASSBYVAL));
10522 }
else if (IsA(c, OpExpr) && list_length(((OpExpr *)c)->args) == 2) {
10523 OpExpr *op = (OpExpr *)c;
10524 Node *l = (Node *)linitial(op->args), *r = (Node *)lsecond(op->args);
10525 SubLink *sl = NULL;
10527 bool sublink_left =
false;
10529 if (IsA(l, SubLink)) {
10532 sublink_left =
true;
10533 }
else if (IsA(r, SubLink)) {
10537 if (sl != NULL && sl->subLinkType == EXPR_SUBLINK &&
10538 IsA(sl->subselect, Query)) {
10539 Query *sub = (Query *)sl->subselect;
10540 if (sub->hasAggs && list_length(sub->targetList) == 1 &&
10541 IsA(((TargetEntry *)linitial(sub->targetList))->expr, Aggref) &&
10543 !contain_vars_of_level(val, 0)) {
10546 copyObject((Node *)((TargetEntry *)linitial(sub->targetList))->expr);
10547 OpExpr *pred = (OpExpr *)copyObject((Node *)op);
10548 pred->args = sublink_left ? list_make2(agg, copyObject(val))
10549 : list_make2(copyObject(val), agg);
10551 }
else if (!sub->hasAggs && list_length(sub->targetList) == 1 &&
10552 !((TargetEntry *)linitial(sub->targetList))->resjunk &&
10555 !contain_vars_of_level(val, 0)) {
10562 Expr *bodyval = ((TargetEntry *)linitial(sub->targetList))->expr;
10564 exprType((Node *)bodyval),
10565 exprType((Node *)bodyval),
10566 (Expr *)copyObject((Node *)bodyval));
10567 OpExpr *cmp = (OpExpr *)copyObject((Node *)op);
10568 Oid leo = OpernameGetOprid(list_make1(makeString(
"<=")), INT8OID,
10570 OpExpr *le1 = makeNode(OpExpr);
10572 cmp->args = sublink_left ? list_make2(ch, copyObject(val))
10573 : list_make2(copyObject(val), ch);
10575 le1->opfuncid = get_opcode(leo);
10576 le1->opresulttype = BOOLOID;
10577 le1->opcollid = InvalidOid;
10578 le1->inputcollid = InvalidOid;
10581 makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
10582 Int64GetDatum(1),
false, FLOAT8PASSBYVAL));
10583 le1->location = -1;
10585 sub, (Node *)makeBoolExpr(AND_EXPR, list_make2(cmp, le1), -1));
10592 RangeTblRef *rtr = makeNode(RangeTblRef);
10593 q->rtable = lappend(q->rtable, d_rte);
10594 rtr->rtindex = list_length(q->rtable);
10595 q->jointree->fromlist = lappend(q->jointree->fromlist, rtr);
10598 newconjs = lappend(newconjs, c);
10604 q->jointree->quals =
10607 : (list_length(newconjs) == 1 ? (Node *)linitial(newconjs)
10608 : (Node *)makeBoolExpr(AND_EXPR, newconjs,
10615 if (q->jointree->quals)
10618 q->hasSubLinks =
false;
10627 OpExpr *op = makeNode(OpExpr);
10629 op->opfuncid = get_opcode(opno);
10630 op->opresulttype = BOOLOID;
10631 op->opcollid = InvalidOid;
10632 op->inputcollid = inputcollid;
10633 op->args = list_make2(cnt, copyObject(constarg));
10642 return DatumGetBool(OidFunctionCall2Coll(get_opcode(opno), c->constcollid,
10643 Int64GetDatum(0), c->constvalue));
10670 List *conjs, *newconjs = NIL;
10672 RangeTblRef *r_ref;
10673 RangeTblEntry *R_rte;
10675 Query *q_body = NULL;
10676 Node *neg_having = NULL;
10678 RangeTblEntry *d_rte;
10681 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
10682 !q->jointree->quals || q->setOperations)
10684 if (list_length(q->jointree->fromlist) != 1 ||
10685 !IsA(linitial(q->jointree->fromlist), RangeTblRef))
10687 r_ref = (RangeTblRef *)linitial(q->jointree->fromlist);
10688 R_idx = r_ref->rtindex;
10689 R_rte = list_nth_node(RangeTblEntry, q->rtable, R_idx - 1);
10693 quals = q->jointree->quals;
10694 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
10695 ? ((BoolExpr *)quals)->args
10696 : list_make1(quals);
10697 foreach (lc, conjs) {
10698 Node *c = (Node *)lfirst(lc);
10700 if (q_body == NULL && IsA(c, BoolExpr) &&
10701 ((BoolExpr *)c)->boolop == NOT_EXPR &&
10702 list_length(((BoolExpr *)c)->args) == 1) {
10704 Node *inner = (Node *)linitial(((BoolExpr *)c)->args);
10705 if (IsA(inner, SubLink) &&
10706 ((SubLink *)inner)->subLinkType == EXISTS_SUBLINK &&
10707 IsA(((SubLink *)inner)->subselect, Query) &&
10709 constants, (Query *)((SubLink *)inner)->subselect)) {
10710 Oid ge = OpernameGetOprid(list_make1(makeString(
">=")), INT8OID,
10712 q_body = (Query *)((SubLink *)inner)->subselect;
10715 (Node *)makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
10716 Int64GetDatum(1),
false, FLOAT8PASSBYVAL));
10719 }
else if (q_body == NULL && IsA(c, OpExpr) &&
10720 list_length(((OpExpr *)c)->args) == 2) {
10722 OpExpr *op = (OpExpr *)c;
10723 Node *l = (Node *)linitial(op->args), *r = (Node *)lsecond(op->args);
10727 if (IsA(l, SubLink) && IsA(r, Const) && !((Const *)r)->constisnull &&
10728 exprType(l) == INT8OID) {
10729 SubLink *sl = (SubLink *)l;
10731 if (sl->subLinkType == EXPR_SUBLINK && IsA(sl->subselect, Query)) {
10732 Query *s = (Query *)sl->subselect;
10733 TargetEntry *te = (list_length(s->targetList) == 1)
10734 ? (TargetEntry *)linitial(s->targetList)
10736 Aggref *cnt = (te && IsA(te->expr, Aggref)) ? (Aggref *)te->expr
10746 OidIsValid((neg = get_negator(op->opno)))) {
10749 neg, op->inputcollid, (Aggref *)copyObject(cnt), r);
10755 newconjs = lappend(newconjs, c);
10757 if (q_body == NULL)
10768 R_idx , &Rc, &Dc, NULL,
10770 lfirst(list_nth_cell(q->rtable, R_idx - 1)) =
10773 q->jointree->quals =
10776 : (list_length(newconjs) == 1
10777 ? (Node *)linitial(newconjs)
10778 : (Node *)makeBoolExpr(AND_EXPR, newconjs, -1));
10786 if (q->jointree->quals)
10789 q->hasSubLinks =
false;
10810 bool changed =
false;
10812 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree)
10815 foreach (lc, q->targetList) {
10816 TargetEntry *te = (TargetEntry *)lfirst(lc);
10819 RangeTblEntry *d_rte;
10824 if (!IsA(te->expr, SubLink))
10826 sl = (SubLink *)te->expr;
10827 if (sl->subLinkType != EXPR_SUBLINK || !IsA(sl->subselect, Query))
10836 rtr = makeNode(RangeTblRef);
10837 dte = (TargetEntry *)linitial(D->targetList);
10838 q->rtable = lappend(q->rtable, d_rte);
10839 d_idx = list_length(q->rtable);
10840 rtr->rtindex = d_idx;
10841 q->jointree->fromlist = lappend(q->jointree->fromlist, rtr);
10842 te->expr = (Expr *)makeVar(d_idx, 1, exprType((Node *)dte->expr),
10843 exprTypmod((Node *)dte->expr),
10844 exprCollation((Node *)dte->expr), 0);
10856 if (q->jointree->quals)
10859 q->hasSubLinks =
false;
10867 Node *n = limitCount;
10871 if (IsA(n, FuncExpr) && list_length(((FuncExpr *)n)->args) == 1)
10872 n = (Node *)linitial(((FuncExpr *)n)->args);
10873 if (IsA(n, RelabelType))
10874 n = (Node *)((RelabelType *)n)->arg;
10875 if (!IsA(n, Const) || ((Const *)n)->constisnull)
10878 if (c->consttype == INT8OID)
10879 return DatumGetInt64(c->constvalue) == 1;
10880 if (c->consttype == INT4OID)
10881 return DatumGetInt32(c->constvalue) == 1;
10882 if (c->consttype == INT2OID)
10883 return DatumGetInt16(c->constvalue) == 1;
10907#if PG_VERSION_NUM >= 160000
10908 return equal(rta, rtb);
10910 RangeTblEntry *a = (RangeTblEntry *)copyObject(linitial(rta));
10911 RangeTblEntry *b = (RangeTblEntry *)copyObject(linitial(rtb));
10912 a->requiredPerms = b->requiredPerms = 0;
10913 a->checkAsUser = b->checkAsUser = InvalidOid;
10914 a->selectedCols = b->selectedCols = NULL;
10915 a->insertedCols = b->insertedCols = NULL;
10916 a->updatedCols = b->updatedCols = NULL;
10917#if PG_VERSION_NUM >= 120000
10918 a->extraUpdatedCols = b->extraUpdatedCols = NULL;
10920 return equal(a, b);
10925 if (a->hasAggs || b->hasAggs || a->distinctClause || b->distinctClause ||
10926 a->sortClause || b->sortClause || a->limitCount || b->limitCount ||
10927 a->limitOffset || b->limitOffset)
10929 if (list_length(a->targetList) != 1 || list_length(b->targetList) != 1 ||
10930 list_length(a->rtable) != 1 || list_length(b->rtable) != 1)
10933 equal(a->jointree, b->jointree);
10950 if (node == NULL || !IsA(node, OpExpr))
10952 nargs = list_length(((OpExpr *)node)->args);
10953 if (nargs < 1 || nargs > 2)
10955 opname = get_opname(((OpExpr *)node)->opno);
10956 if (opname == NULL)
10958 is_arith = strcmp(opname,
"+") == 0 || strcmp(opname,
"-") == 0 ||
10959 strcmp(opname,
"*") == 0 || strcmp(opname,
"/") == 0;
10982 if (node == (Node *)sl)
10986 foreach (lc, ((OpExpr *)node)->args)
11010 if (node == (Node *)c->
target)
11027 RangeTblRef *r_ref;
11028 Index R_idx, Q_idx, join_idx;
11029 RangeTblEntry *R_rte, *Q_rte_orig, *Q_copy, *jrte;
11031 SubLink *sl = NULL;
11032 TargetEntry *sl_te = NULL;
11039 int i, n_tl_sublinks = 0;
11040 bool in_where =
false;
11041 bool is_agg_body =
false;
11042 bool is_limit1 =
false;
11043 bool is_distinct =
false;
11044 bool coalesce =
false;
11045 bool nested_in_tl =
false;
11046 List *co_sls = NIL, *co_tes = NIL;
11051 if (q->commandType != CMD_SELECT || !q->hasSubLinks)
11053 if (q->groupClause || q->groupingSets || q->hasAggs || q->distinctClause ||
11054 q->setOperations || q->havingQual || q->hasWindowFuncs)
11056 if (!q->jointree || q->jointree->fromlist == NIL)
11068 if (q->jointree->quals)
11079 foreach (lc, q->targetList) {
11080 TargetEntry *te = (TargetEntry *)lfirst(lc);
11082 if (te->expr == NULL || !IsA(te->expr, SubLink))
11084 e = (SubLink *)te->expr;
11085 if (e->subLinkType != EXPR_SUBLINK || !IsA(e->subselect, Query))
11088 rep = (Query *)e->subselect;
11091 co_sls = lappend(co_sls, e);
11092 co_tes = lappend(co_tes, te);
11098 sl = (SubLink *)linitial(co_sls);
11099 sl_te = (TargetEntry *)linitial(co_tes);
11104 if (sl == NULL || sl->subLinkType != EXPR_SUBLINK ||
11105 !IsA(sl->subselect, Query))
11111 foreach (lc, q->targetList) {
11112 TargetEntry *te = (TargetEntry *)lfirst(lc);
11113 if (te->expr == (Expr *)sl) {
11118 if (sl_te == NULL) {
11119 if (n_tl_sublinks > 0) {
11126 foreach (lc, q->targetList) {
11127 TargetEntry *te = (TargetEntry *)lfirst(lc);
11130 nested_in_tl =
true;
11143 List *direct = NIL;
11145 if (!list_member_ptr(direct, sl))
11157 sub = (Query *)sl->subselect;
11158 if (sub->commandType != CMD_SELECT || sub->groupClause ||
11159 sub->groupingSets || sub->setOperations || sub->hasWindowFuncs ||
11160 sub->hasSubLinks || sub->limitOffset || sub->cteList)
11165 if (sub->distinctClause != NIL) {
11166 if (sub->hasDistinctOn || sub->hasAggs || sub->limitCount)
11168 is_distinct =
true;
11173 if (sub->limitCount) {
11174 if (!sub->sortClause || sub->hasAggs ||
11184 foreach (tlc, sub->targetList)
11185 if (!((TargetEntry *)lfirst(tlc))->resjunk)
11187 if (nreal != 1 || ((TargetEntry *)linitial(sub->targetList))->resjunk)
11190 if (sub->hasAggs &&
11191 !IsA(((TargetEntry *)linitial(sub->targetList))->expr, Aggref))
11193 is_agg_body = sub->hasAggs;
11194 if (!sub->jointree || sub->jointree->fromlist == NIL)
11201 if (list_length(sub->jointree->fromlist) != 1 ||
11202 !IsA(linitial(sub->jointree->fromlist), RangeTblRef))
11204 Q_rte_orig = list_nth_node(RangeTblEntry, sub->rtable, 0);
11205 if ((Q_rte_orig->rtekind != RTE_RELATION &&
11206 !(Q_rte_orig->rtekind == RTE_SUBQUERY && !Q_rte_orig->lateral)) ||
11215 if (list_length(q->jointree->fromlist) == 1 &&
11216 IsA(linitial(q->jointree->fromlist), RangeTblRef)) {
11217 r_ref = (RangeTblRef *)linitial(q->jointree->fromlist);
11218 R_rte = list_nth_node(RangeTblEntry, q->rtable, r_ref->rtindex - 1);
11219 if ((R_rte->rtekind == RTE_RELATION ||
11220 (R_rte->rtekind == RTE_SUBQUERY && !R_rte->lateral)) &&
11222 R_idx = r_ref->rtindex;
11226 if (R_rte == NULL) {
11241 R_rte = list_nth_node(RangeTblEntry, q->rtable, 0);
11242 sub = (Query *)sl->subselect;
11246 foreach (lc, q->targetList) {
11247 TargetEntry *te = (TargetEntry *)lfirst(lc);
11248 if (te->expr == (Expr *)sl) {
11266 if (sub->jointree->quals)
11270 ((Aggref *)((TargetEntry *)linitial(sub->targetList))->expr)->aggstar))
11278 Q_copy = copyObject(Q_rte_orig);
11279#if PG_VERSION_NUM >= 160000
11280 if (Q_rte_orig->perminfoindex != 0) {
11281 RTEPermissionInfo *pi =
11282 getRTEPermissionInfo(sub->rteperminfos, Q_rte_orig);
11283 q->rteperminfos = lappend(q->rteperminfos, copyObject(pi));
11284 Q_copy->perminfoindex = list_length(q->rteperminfos);
11287 q->rtable = lappend(q->rtable, Q_copy);
11288 Q_idx = list_length(q->rtable);
11293 dctx.
q_new = Q_idx;
11296 copyObject((Node *)((TargetEntry *)linitial(sub->targetList))->expr),
11302 List *av = NIL, *lcols = NIL, *rcols = NIL, *cn = NIL;
11303 jrte = makeNode(RangeTblEntry);
11304 for (i = 0; i < Rc.
n; ++i) {
11305 av = lappend(av, makeVar(R_idx, Rc.
attno[i], Rc.
type[i], Rc.
typmod[i],
11307 lcols = lappend_int(lcols, Rc.
attno[i]);
11308 rcols = lappend_int(rcols, 0);
11309 cn = lappend(cn, makeString(pstrdup(Rc.
name[i])));
11311 for (i = 0; i < Qc.
n; ++i) {
11312 av = lappend(av, makeVar(Q_idx, Qc.
attno[i], Qc.
type[i], Qc.
typmod[i],
11314 lcols = lappend_int(lcols, 0);
11315 rcols = lappend_int(rcols, Qc.
attno[i]);
11316 cn = lappend(cn, makeString(pstrdup(Qc.
name[i])));
11318 jrte->rtekind = RTE_JOIN;
11319 jrte->jointype = JOIN_LEFT;
11320 jrte->alias = NULL;
11322 jrte->joinaliasvars = av;
11323#if PG_VERSION_NUM >= 130000
11324 jrte->joinleftcols = lcols;
11325 jrte->joinrightcols = rcols;
11326 jrte->joinmergedcols = 0;
11328 jrte->inFromCl =
true;
11329 q->rtable = lappend(q->rtable, jrte);
11330 join_idx = list_length(q->rtable);
11334 JoinExpr *je = makeNode(JoinExpr);
11335 RangeTblRef *lr = makeNode(RangeTblRef), *rr = makeNode(RangeTblRef);
11336 lr->rtindex = R_idx;
11337 rr->rtindex = Q_idx;
11338 je->jointype = JOIN_LEFT;
11339 je->larg = (Node *)lr;
11340 je->rarg = (Node *)rr;
11342 je->isNatural =
false;
11343 je->usingClause = NIL;
11344 je->rtindex = join_idx;
11345 q->jointree->fromlist = list_make1(je);
11357 Aggref *agg = (Aggref *)valexpr;
11358 if (agg->aggstar) {
11364 if (Q_rte_orig->rtekind == RTE_SUBQUERY) {
11366 foreach (klc, Q_rte_orig->subquery->targetList) {
11367 TargetEntry *kte = (TargetEntry *)lfirst(klc);
11368 if (!kte->resjunk && kte->resname &&
11370 qkey = makeVar(Q_idx, kte->resno, BOOLOID, -1, InvalidOid, 0);
11375 if (qkey == NULL) {
11376 qkey = (Var *)copyObject(scan.
found_var);
11377 qkey->varno = Q_idx;
11378#if PG_VERSION_NUM >= 130000
11379 qkey->varnosyn = 0;
11380 qkey->varattnosyn = 0;
11386 repl_expr = valexpr;
11388 }
else if (is_limit1) {
11393 Aggref *agg = makeNode(Aggref);
11394 List *new_args = NIL;
11396 foreach (alc, sub->targetList) {
11397 TargetEntry *te = (TargetEntry *)copyObject(lfirst(alc));
11399 new_args = lappend(new_args, te);
11402 agg->aggtype = exprType((Node *)valexpr);
11403 agg->aggtranstype = InvalidOid;
11404 agg->aggargtypes = list_make1_oid(exprType((Node *)valexpr));
11405 agg->args = new_args;
11406 agg->aggorder = (List *)copyObject((Node *)sub->sortClause);
11407 agg->aggkind = AGGKIND_NORMAL;
11408 agg->aggsplit = AGGSPLIT_SIMPLE;
11409 agg->location = -1;
11410#if PG_VERSION_NUM >= 140000
11411 agg->aggno = agg->aggtransno = -1;
11413 repl_expr = (Expr *)agg;
11416 exprType((Node *)valexpr),
11417 exprType((Node *)valexpr), valexpr);
11425 forboth(la, co_sls, lb, co_tes) {
11426 SubLink *sli = (SubLink *)lfirst(la);
11427 TargetEntry *tei = (TargetEntry *)lfirst(lb);
11430 (Node *)((TargetEntry *)linitial(((Query *)sli->subselect)->targetList))
11434 exprType((Node *)vi),
11435 exprType((Node *)vi), vi);
11437 }
else if (nested_in_tl) {
11443 rc.
repl = (Node *)repl_expr;
11445 }
else if (!in_where)
11446 sl_te->expr = repl_expr;
11453 foreach (lc, q->targetList) {
11454 TargetEntry *te = (TargetEntry *)lfirst(lc);
11455 if (te->ressortgroupref > sgref)
11456 sgref = te->ressortgroupref;
11458 for (i = 0; i < Rc.
n; ++i) {
11459 TargetEntry *gte = NULL;
11460 SortGroupClause *sgc;
11464 foreach (lc2, q->targetList) {
11465 TargetEntry *te = (TargetEntry *)lfirst(lc2);
11466 if (IsA(te->expr, Var)) {
11467 Var *v = (Var *)te->expr;
11468 if (v->varlevelsup == 0 && v->varno == R_idx &&
11469 v->varattno == Rc.
attno[i]) {
11478 gte = makeTargetEntry((Expr *)v, list_length(q->targetList) + 1,
11479 pstrdup(Rc.
name[i]),
true );
11480 q->targetList = lappend(q->targetList, gte);
11482 if (gte->ressortgroupref == 0)
11483 gte->ressortgroupref = ++sgref;
11484 sgc = makeNode(SortGroupClause);
11485 sgc->tleSortGroupRef = gte->ressortgroupref;
11486 get_sort_group_operators(Rc.
type[i],
false,
true,
false, &sgc->sortop,
11487 &sgc->eqop, NULL, &sgc->hashable);
11488 q->groupClause = lappend(q->groupClause, sgc);
11499 List *having_conjuncts = NIL;
11501 if (!is_agg_body && !is_limit1) {
11504 having_conjuncts = list_make1(
11514 having_conjuncts = lappend(
11524 Node *quals = q->jointree->quals;
11526 (quals && IsA(quals, BoolExpr) &&
11527 ((BoolExpr *)quals)->boolop == AND_EXPR)
11528 ? ((BoolExpr *)quals)->args
11529 : (quals ? list_make1(quals) : NIL);
11535 foreach (lc2, conjs) {
11536 Node *c = (Node *)lfirst(lc2);
11541 kept = lappend(kept, c);
11543 q->jointree->quals =
11544 (kept == NIL) ? NULL
11545 : (list_length(kept) == 1 ? (Node *)linitial(kept)
11546 : (Node *)makeBoolExpr(
11547 AND_EXPR, kept, -1));
11551 (having_conjuncts == NIL)
11553 : (list_length(having_conjuncts) == 1
11554 ? (Node *)linitial(having_conjuncts)
11555 : (Node *)makeBoolExpr(AND_EXPR, having_conjuncts, -1));
11559 q->hasSubLinks =
false;
11593 SetOperationStmt *so;
11594 RangeTblRef *rarg_ref;
11595 RangeTblEntry *rarg_rte;
11597 RangeTblEntry *w_rte;
11602 int colno = 0, sgref = 0;
11603 bool any_group =
false;
11607 if (q->setOperations == NULL || !IsA(q->setOperations, SetOperationStmt))
11609 so = (SetOperationStmt *)q->setOperations;
11610 if (so->op != SETOP_EXCEPT)
11614 if (!IsA(so->rarg, RangeTblRef))
11616 rarg_ref = (RangeTblRef *)so->rarg;
11617 rarg_rte = list_nth_node(RangeTblEntry, q->rtable, rarg_ref->rtindex - 1);
11618 if (rarg_rte->rtekind != RTE_SUBQUERY || rarg_rte->subquery == NULL)
11620 origB = rarg_rte->subquery;
11625 if (origB->groupClause != NIL || origB->groupingSets != NIL)
11628 G = makeNode(Query);
11629 G->commandType = CMD_SELECT;
11630 G->canSetTag =
true;
11632 G->rtable = list_make1(w_rte);
11633 rtr = makeNode(RangeTblRef);
11635 fe = makeNode(FromExpr);
11636 fe->fromlist = list_make1(rtr);
11640 foreach (lc, origB->targetList) {
11641 TargetEntry *te = (TargetEntry *)lfirst(lc);
11644 SortGroupClause *sgc;
11651 coltype = exprType((Node *)te->expr);
11652 v = makeVar(1, colno, coltype, exprTypmod((Node *)te->expr),
11653 exprCollation((Node *)te->expr), 0);
11654 nte = makeTargetEntry((Expr *)v, list_length(tl) + 1,
11655 te->resname ? pstrdup(te->resname) : NULL,
false);
11659 sgc = makeNode(SortGroupClause);
11660 sgc->tleSortGroupRef = nte->ressortgroupref = ++sgref;
11661 get_sort_group_operators(coltype,
false,
true,
false, &sgc->sortop,
11662 &sgc->eqop, NULL, &sgc->hashable);
11663 G->groupClause = lappend(G->groupClause, sgc);
11666 tl = lappend(tl, nte);
11668 G->targetList = tl;
11673 rarg_rte->subquery = G;
11690 SetOperationStmt *stmt,
11692 if (stmt->op != SETOP_UNION) {
11695 if (IsA(stmt->larg, SetOperationStmt)) {
11698 if (IsA(stmt->rarg, SetOperationStmt)) {
11704 if (IsA(stmt->larg, RangeTblRef)) {
11705 Index rtindex = ((RangeTblRef *)stmt->larg)->rtindex;
11706 RangeTblEntry *rte = list_nth_node(RangeTblEntry, q->rtable, rtindex - 1);
11707 if (rte->rtekind == RTE_SUBQUERY && rte->subquery != NULL) {
11708 ListCell *lc_type = list_head(stmt->colTypes);
11709 ListCell *lc_te = list_head(rte->subquery->targetList);
11710 while (lc_type != NULL && lc_te != NULL) {
11711 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
11715 lc_type =
my_lnext(stmt->colTypes, lc_type);
11716 lc_te =
my_lnext(rte->subquery->targetList, lc_te);
11721 stmt->colTypes = lappend_oid(stmt->colTypes, constants->
OID_TYPE_UUID);
11722 stmt->colTypmods = lappend_int(stmt->colTypmods, -1);
11723 stmt->colCollations = lappend_int(stmt->colCollations, 0);
11741 FuncExpr *
gate_zero = makeNode(FuncExpr);
11742 OpExpr *oe = makeNode(OpExpr);
11749 oe->opresulttype = BOOLOID;
11753 if (q->jointree->quals != NULL) {
11754 BoolExpr *be = makeNode(BoolExpr);
11756 be->boolop = AND_EXPR;
11757 be->args = list_make2(oe, q->jointree->quals);
11760 q->jointree->quals = (Node *)be;
11762 q->jointree->quals = (Node *)oe;
11779 havingQual = (Node*) expr;
11780 }
else if(IsA(havingQual, BoolExpr) && ((BoolExpr*)havingQual)->boolop==AND_EXPR) {
11781 BoolExpr *be = (BoolExpr*)havingQual;
11782 be->args = lappend(be->args, expr);
11783 }
else if(IsA(havingQual, OpExpr) || IsA(havingQual, BoolExpr)) {
11785 BoolExpr *be = makeNode(BoolExpr);
11786 be->boolop=AND_EXPR;
11788 be->args = list_make2(havingQual, expr);
11789 havingQual = (Node*) be;
11791 provsql_error(
"Unknown structure within Boolean expression");
11813 if(op->args->length != 2)
11816 for(
unsigned i=0; i<2; ++i) {
11817 Node *arg = lfirst(list_nth_cell(op->args, i));
11828 return agg_sides >= 1;
11846 foreach (lc, be->args) {
11847 Node *n=lfirst(lc);
11854 if(IsA(n, OpExpr)) {
11857 }
else if(IsA(n, BoolExpr)) {
11875 switch(expr->type) {
11888 provsql_error(
"Unknown structure within Boolean expression");
11926 foreach (l, q->rtable) {
11927 RangeTblEntry *r = (RangeTblEntry *)lfirst(l);
11931 if (r->eref && r->eref->colnames != NIL) {
11934 columns[i] = (
int *)palloc(list_length(r->eref->colnames) *
sizeof(
int));
11936 foreach (lc, r->eref->colnames) {
11939 columns[i][j] = ++(*nbcols);
11941 const char *v = strVal(lfirst(lc));
11943 if (strcmp(v,
"") && r->rtekind != RTE_JOIN) {
11945 columns[i][j] = -1;
11947 columns[i][j] = ++(*nbcols);
12003 if (has_agg && has_rv)
12031 provsql_error(
"Unsupported aggregate comparison shape in the selection "
12038 provsql_error(
"Unsupported random_variable comparison shape in the "
12042 provsql_error(
"WHERE clause mixes agg_token (HAVING-style) and "
12043 "random_variable (per-tuple) comparisons inside the "
12044 "same Boolean expression; this combination is not "
12082 List *rv_cmps = NIL;
12085 if (!q->jointree || !q->jointree->quals)
12088 quals = q->jointree->quals;
12094 if (!IsA(quals, BoolExpr) || ((BoolExpr *)quals)->boolop != AND_EXPR) {
12101 q->jointree->quals = NULL;
12104 rv_cmps = lappend(rv_cmps,
12106 constants,
false));
12107 q->jointree->quals = NULL;
12121 BoolExpr *be = (BoolExpr *)quals;
12122 ListCell *cell, *prev;
12124 for (cell = list_head(be->args), prev = NULL; cell != NULL;) {
12125 Expr *conjunct = (Expr *)lfirst(cell);
12137 cell = list_head(be->args);
12140 rv_cmps = lappend(rv_cmps,
12142 constants,
false));
12147 cell = list_head(be->args);
12160 if (be->args == NIL)
12161 q->jointree->quals = NULL;
12162 else if (list_length(be->args) == 1)
12163 q->jointree->quals = (Node *)linitial(be->args);
12183 RangeTblEntry *rte;
12186 if (v->varno < 1 || v->varno > list_length(ctx->
query->rtable))
12189 rte = list_nth_node(RangeTblEntry, ctx->
query->rtable, v->varno - 1);
12190 if (rte->rtekind != RTE_SUBQUERY || rte->subquery == NULL)
12193 if (v->varattno < 1 || v->varattno > list_length(rte->subquery->targetList))
12196 te = list_nth_node(TargetEntry, rte->subquery->targetList, v->varattno - 1);
12197 if (IsA(te->expr, FuncExpr)) {
12198 FuncExpr *f = (FuncExpr *)te->expr;
12200 Const *aggtype_const = (Const *)lsecond(f->args);
12201 return DatumGetObjectId(aggtype_const->constvalue);
12212 Var *v = (Var *)lfirst(lc);
12214 HeapTuple castTuple;
12216 if (!OidIsValid(target))
12219 castTuple = SearchSysCache2(CASTSOURCETARGET,
12221 ObjectIdGetDatum(target));
12222 if (HeapTupleIsValid(castTuple)) {
12223 Form_pg_cast castForm = (Form_pg_cast)GETSTRUCT(castTuple);
12224 if (OidIsValid(castForm->castfunc)) {
12225 FuncExpr *fc = makeNode(FuncExpr);
12226 fc->funcid = castForm->castfunc;
12227 fc->funcresulttype = target;
12228 fc->funcretset =
false;
12229 fc->funcvariadic =
false;
12230 fc->funcformat = COERCE_IMPLICIT_CAST;
12231 fc->funccollid = InvalidOid;
12232 fc->inputcollid = InvalidOid;
12233 fc->args = list_make1(v);
12237 ReleaseSysCache(castTuple);
12247 foreach (lc, args) {
12248 if (IsA(lfirst(lc), Var) &&
12270 if (IsA(node, OpExpr)) {
12275 if (swapped != NULL)
12278 return (Node *)node;
12280 if (IsA(node, WindowFunc)) {
12282 return (Node *)node;
12284 if (IsA(node, CoalesceExpr)) {
12286 return (Node *)node;
12288 if (IsA(node, MinMaxExpr)) {
12290 return (Node *)node;
12292 if (IsA(node, NullIfExpr)) {
12294 return (Node *)node;
12306 QTW_DONT_COPY_QUERY | QTW_IGNORE_RC_SUBQUERIES);
12321 if (IsA(node, OpExpr)) {
12322 OpExpr *oe = (OpExpr *) node;
12323 Node *left = (Node *) linitial(oe->args);
12324 Node *right = (Node *) lsecond(oe->args);
12327 if (IsA(left, FuncExpr) &&
12328 (((FuncExpr *)left)->funcformat == COERCE_IMPLICIT_CAST ||
12329 ((FuncExpr *)left)->funcformat == COERCE_EXPLICIT_CAST) &&
12330 list_length(((FuncExpr *)left)->args) == 1)
12331 left = linitial(((FuncExpr *)left)->args);
12332 if (IsA(right, FuncExpr) &&
12333 (((FuncExpr *)right)->funcformat == COERCE_IMPLICIT_CAST ||
12334 ((FuncExpr *)right)->funcformat == COERCE_EXPLICIT_CAST) &&
12335 list_length(((FuncExpr *)right)->args) == 1)
12336 right = linitial(((FuncExpr *)right)->args);
12338 if (IsA(left, Var) && IsA(right, Var)) {
12339 Var *left_var = (Var *)left;
12340 Var *right_var = (Var *)right;
12343 *ctx->
rteid = left_var->varno;
12349 *ctx->
rteid = right_var->varno;
12374 Index *rteid, AttrNumber *join_attno)
12397 Const *idx = makeConst(INT4OID, -1, InvalidOid,
sizeof(int32),
12398 Int32GetDatum(index),
false,
true);
12399#if PG_VERSION_NUM >= 120000
12400 SubscriptingRef *sub = makeNode(SubscriptingRef);
12403#if PG_VERSION_NUM >= 140000
12406 sub->reftypmod = -1;
12407 sub->refcollid = InvalidOid;
12408 sub->refupperindexpr = list_make1(idx);
12409 sub->reflowerindexpr = NIL;
12410 sub->refexpr = (Expr *)arr_expr;
12411 sub->refassgnexpr = NULL;
12412 return (Node *)sub;
12414 ArrayRef *sub = makeNode(ArrayRef);
12417 sub->reftypmod = -1;
12418 sub->refcollid = InvalidOid;
12419 sub->refupperindexpr = list_make1(idx);
12420 sub->reflowerindexpr = NIL;
12421 sub->refexpr = (Expr *)arr_expr;
12422 sub->refassgnexpr = NULL;
12423 return (Node *)sub;
12453 if (IsA(node, OpExpr)) {
12454 OpExpr *oe = (OpExpr *)node;
12455 if (list_length(oe->args) == 2) {
12456 Node *left = (Node *)linitial(oe->args);
12457 Node *right = (Node *)lsecond(oe->args);
12459 bool agg_on_left =
false;
12461 if (IsA(left, Var)) {
12462 Var *v = (Var *)left;
12463 if (v->varlevelsup == 0 && v->varno == ctx->
rteid &&
12467 agg_on_left =
true;
12470 if (agg_v == NULL && IsA(right, Var)) {
12471 Var *v = (Var *)right;
12472 if (v->varlevelsup == 0 && v->varno == ctx->
rteid &&
12479 if (agg_v != NULL) {
12480 Node *other = agg_on_left ? right : left;
12483 Form_pg_operator opform;
12485 agg_v->vartype = TEXTOID;
12486 agg_v->varcollid = DEFAULT_COLLATION_OID;
12488 if (exprType(other) != TEXTOID) {
12489 CoerceViaIO *c = makeNode(CoerceViaIO);
12490 c->arg = (Expr *)other;
12491 c->resulttype = TEXTOID;
12492 c->resultcollid = DEFAULT_COLLATION_OID;
12493 c->coerceformat = COERCE_EXPLICIT_CAST;
12499 oe->args = list_make2(agg_v, other);
12501 oe->args = list_make2(other, agg_v);
12504 if (!OidIsValid(text_eq))
12505 provsql_error(
"rewrite_join_agg_token: text = text operator "
12507 opInfo = SearchSysCache1(OPEROID, ObjectIdGetDatum(text_eq));
12508 if (!HeapTupleIsValid(opInfo))
12510 "text equality operator");
12511 opform = (Form_pg_operator)GETSTRUCT(opInfo);
12512 oe->opno = text_eq;
12513 oe->opfuncid = opform->oprcode;
12514 oe->opresulttype = opform->oprresult;
12515 oe->inputcollid = DEFAULT_COLLATION_OID;
12516 ReleaseSysCache(opInfo);
12524 if (IsA(node, Var)) {
12525 Var *v = (Var *)node;
12526 if (v->varlevelsup == 0 && v->varno == ctx->
rteid &&
12529 v->vartype = TEXTOID;
12530 v->varcollid = DEFAULT_COLLATION_OID;
12535 if (IsA(node, Query)) {
12555 if (IsA(node, Aggref)) {
12556 *(
bool *) found =
true;
12559 if (IsA(node, Query))
12573 bool found =
false;
12590 Node *arg = (Node *) nt->arg;
12592 RangeTblEntry *rte;
12596 if (IsA(arg, FuncExpr)) {
12597 FuncExpr *fe = (FuncExpr *) arg;
12598 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
12599 fe->funcformat == COERCE_EXPLICIT_CAST) &&
12600 list_length(fe->args) == 1)
12601 arg = (Node *) linitial(fe->args);
12604 if (!IsA(arg, Var))
12607 if (v->varlevelsup != 0 || v->varno < 1 ||
12608 v->varno > (Index) list_length(q->rtable))
12616 if (v->varlevelsup != 0 || v->varno < 1 ||
12617 v->varno > (Index) list_length(q->rtable))
12619 rte = (RangeTblEntry *) list_nth(q->rtable, v->varno - 1);
12620 if (rte->rtekind != RTE_SUBQUERY || rte->subquery == NULL)
12622 sub = rte->subquery;
12623 if (v->varattno < 1 || v->varattno > list_length(sub->targetList))
12626 te = (TargetEntry *) list_nth(sub->targetList, v->varattno - 1);
12630 if (IsA(te->expr, Var)) {
12632 v = (Var *) te->expr;
12658 down = (NullTest *) copyObject(nt);
12659 down->arg = (Expr *) copyObject(te->expr);
12692 if (q->jointree == NULL || q->jointree->quals == NULL)
12699 quals = q->jointree->quals;
12702 if (IsA(quals, NullTest)) {
12705 q->jointree->quals = NULL;
12712 if (IsA(quals, BoolExpr) && ((BoolExpr *) quals)->boolop == AND_EXPR) {
12713 BoolExpr *be = (BoolExpr *) quals;
12714 ListCell *cell, *prev;
12716 for (cell = list_head(be->args), prev = NULL; cell != NULL;) {
12717 Node *conj = (Node *) lfirst(cell);
12719 if (IsA(conj, NullTest) &&
12722 cell = prev ?
my_lnext(be->args, prev) : list_head(be->args);
12733 if (be->args == NIL)
12734 q->jointree->quals = NULL;
12735 else if (list_length(be->args) == 1)
12736 q->jointree->quals = (Node *) linitial(be->args);
12777 Index rteid, AttrNumber join_attno)
12779 RangeTblEntry *src_rte = (RangeTblEntry *)list_nth(q->rtable, rteid - 1);
12780 AttrNumber provsql_attno = 0;
12784 RangeTblEntry *inner_src, *sm_rte;
12785 RangeTblFunction *rtfunc;
12786 FuncExpr *unnest_call, *get_children_of_agg, *agg_to_uuid;
12787 Var *agg_var_in_inner;
12788 Alias *sm_alias, *sm_eref;
12789 RangeTblRef *inner_rtr1, *inner_rtr2;
12790 FromExpr *inner_jt;
12791 List *inner_tl = NIL;
12793 if (src_rte->rtekind != RTE_RELATION && src_rte->rtekind != RTE_SUBQUERY)
12794 provsql_error(
"rewrite_join_agg_token: source RTE kind %d not supported",
12795 (
int)src_rte->rtekind);
12799 foreach (lc, src_rte->eref->colnames) {
12801 provsql_attno = attno;
12806 if (provsql_attno == 0)
12807 provsql_error(
"rewrite_join_agg_token: source relation has no "
12812 agg_var_in_inner = makeNode(Var);
12813 agg_var_in_inner->varno = 1;
12814 agg_var_in_inner->varattno = join_attno;
12816 agg_var_in_inner->varcollid = InvalidOid;
12817 agg_var_in_inner->vartypmod = -1;
12818 agg_var_in_inner->location = -1;
12820 agg_to_uuid = makeNode(FuncExpr);
12823 agg_to_uuid->funcretset =
false;
12824 agg_to_uuid->funcvariadic =
false;
12825 agg_to_uuid->funcformat = COERCE_IMPLICIT_CAST;
12826 agg_to_uuid->funccollid = InvalidOid;
12827 agg_to_uuid->inputcollid = InvalidOid;
12828 agg_to_uuid->args = list_make1(agg_var_in_inner);
12829 agg_to_uuid->location = -1;
12831 get_children_of_agg = makeNode(FuncExpr);
12834 get_children_of_agg->funcretset =
false;
12835 get_children_of_agg->funcvariadic =
false;
12836 get_children_of_agg->funcformat = COERCE_EXPLICIT_CALL;
12837 get_children_of_agg->funccollid = InvalidOid;
12838 get_children_of_agg->inputcollid = InvalidOid;
12839 get_children_of_agg->args = list_make1(agg_to_uuid);
12840 get_children_of_agg->location = -1;
12842 unnest_call = makeNode(FuncExpr);
12843 unnest_call->funcid = constants->
OID_UNNEST;
12845 unnest_call->funcretset =
true;
12846 unnest_call->funcvariadic =
false;
12847 unnest_call->funcformat = COERCE_EXPLICIT_CALL;
12848 unnest_call->funccollid = InvalidOid;
12849 unnest_call->inputcollid = InvalidOid;
12850 unnest_call->args = list_make1(get_children_of_agg);
12851 unnest_call->location = -1;
12853 rtfunc = makeNode(RangeTblFunction);
12854 rtfunc->funcexpr = (Node *)unnest_call;
12855 rtfunc->funccolcount = 1;
12856 rtfunc->funccolnames = NIL;
12857 rtfunc->funccoltypes = NIL;
12858 rtfunc->funccoltypmods = NIL;
12859 rtfunc->funccolcollations = NIL;
12860 rtfunc->funcparams = NULL;
12862 sm_alias = makeNode(Alias);
12863 sm_eref = makeNode(Alias);
12864 sm_alias->aliasname =
"sm";
12865 sm_eref->aliasname =
"sm";
12866 sm_eref->colnames = list_make1(makeString(
"sm"));
12868 sm_rte = makeNode(RangeTblEntry);
12869 sm_rte->rtekind = RTE_FUNCTION;
12870 sm_rte->functions = list_make1(rtfunc);
12871 sm_rte->funcordinality =
false;
12872 sm_rte->alias = sm_alias;
12873 sm_rte->eref = sm_eref;
12874 sm_rte->lateral =
true;
12875 sm_rte->inFromCl =
true;
12876#if PG_VERSION_NUM < 160000
12877 sm_rte->requiredPerms = 0;
12882 inner_src = copyObject(src_rte);
12890 inner_rtr1 = makeNode(RangeTblRef);
12891 inner_rtr1->rtindex = 1;
12892 inner_rtr2 = makeNode(RangeTblRef);
12893 inner_rtr2->rtindex = 2;
12894 inner_jt = makeNode(FromExpr);
12895 inner_jt->fromlist = list_make2(inner_rtr1, inner_rtr2);
12896 inner_jt->quals = NULL;
12901 foreach (lc, src_rte->eref->colnames) {
12902 const char *colname = strVal(lfirst(lc));
12903 TargetEntry *te = makeNode(TargetEntry);
12905 te->resname = pstrdup(colname);
12906 te->resjunk =
false;
12908 if (attno == join_attno) {
12910 Var *sm_var = makeNode(Var);
12911 FuncExpr *gch, *ge;
12915 sm_var->varattno = 1;
12917 sm_var->varcollid = InvalidOid;
12918 sm_var->vartypmod = -1;
12919 sm_var->location = -1;
12921 gch = makeNode(FuncExpr);
12924 gch->funcretset =
false;
12925 gch->funcvariadic =
false;
12926 gch->funcformat = COERCE_EXPLICIT_CALL;
12927 gch->funccollid = InvalidOid;
12928 gch->inputcollid = InvalidOid;
12929 gch->args = list_make1(sm_var);
12930 gch->location = -1;
12934 ge = makeNode(FuncExpr);
12936 ge->funcresulttype = TEXTOID;
12937 ge->funcretset =
false;
12938 ge->funcvariadic =
false;
12939 ge->funcformat = COERCE_EXPLICIT_CALL;
12940 ge->funccollid = DEFAULT_COLLATION_OID;
12941 ge->inputcollid = InvalidOid;
12942 ge->args = list_make1(subscript);
12945 te->expr = (Expr *)ge;
12946 }
else if (attno == provsql_attno) {
12948 Var *sm_var = makeNode(Var);
12949 Var *prov_var = makeNode(Var);
12950 FuncExpr *gch, *pt;
12955 sm_var->varattno = 1;
12957 sm_var->varcollid = InvalidOid;
12958 sm_var->vartypmod = -1;
12959 sm_var->location = -1;
12961 gch = makeNode(FuncExpr);
12964 gch->funcretset =
false;
12965 gch->funcvariadic =
false;
12966 gch->funcformat = COERCE_EXPLICIT_CALL;
12967 gch->funccollid = InvalidOid;
12968 gch->inputcollid = InvalidOid;
12969 gch->args = list_make1(sm_var);
12970 gch->location = -1;
12974 prov_var->varno = 1;
12975 prov_var->varattno = provsql_attno;
12977 prov_var->varcollid = InvalidOid;
12978 prov_var->vartypmod = -1;
12979 prov_var->location = -1;
12981 arr = makeNode(ArrayExpr);
12984 arr->elements = list_make2(subscript, prov_var);
12985 arr->location = -1;
12987 pt = makeNode(FuncExpr);
12990 pt->funcretset =
false;
12991 pt->funcvariadic =
true;
12992 pt->funcformat = COERCE_EXPLICIT_CALL;
12993 pt->funccollid = InvalidOid;
12994 pt->inputcollid = InvalidOid;
12995 pt->args = list_make1(arr);
12998 te->expr = (Expr *)pt;
13001 Var *v = makeNode(Var);
13002 Oid vtype = InvalidOid;
13003 int32 vtypmod = -1;
13004 Oid vcoll = InvalidOid;
13006 if (src_rte->rtekind == RTE_RELATION) {
13007 get_atttypetypmodcoll(src_rte->relid, attno, &vtype, &vtypmod, &vcoll);
13009 TargetEntry *sub_te =
13010 (TargetEntry *)list_nth(src_rte->subquery->targetList, attno - 1);
13011 vtype = exprType((Node *)sub_te->expr);
13012 vtypmod = exprTypmod((Node *)sub_te->expr);
13013 vcoll = exprCollation((Node *)sub_te->expr);
13017 v->varattno = attno;
13018 v->vartype = vtype;
13019 v->varcollid = vcoll;
13020 v->vartypmod = vtypmod;
13022 te->expr = (Expr *)v;
13025 inner_tl = lappend(inner_tl, te);
13029 inner = makeNode(Query);
13030 inner->commandType = CMD_SELECT;
13031 inner->canSetTag =
true;
13032 inner->rtable = list_make2(inner_src, sm_rte);
13033 inner->jointree = inner_jt;
13034 inner->targetList = inner_tl;
13035 inner->hasAggs =
false;
13036 inner->hasSubLinks =
false;
13038#if PG_VERSION_NUM >= 160000
13044 if (inner_src->perminfoindex != 0) {
13045 RTEPermissionInfo *perminfo =
13046 getRTEPermissionInfo(q->rteperminfos, src_rte);
13047 inner->rteperminfos = list_make1(copyObject(perminfo));
13048 inner_src->perminfoindex = 1;
13054 src_rte->rtekind = RTE_SUBQUERY;
13055 src_rte->subquery = inner;
13056 src_rte->relid = InvalidOid;
13057 src_rte->relkind = 0;
13058#if PG_VERSION_NUM >= 120000
13059 src_rte->rellockmode = 0;
13061 src_rte->inh =
false;
13062 src_rte->lateral =
false;
13063#if PG_VERSION_NUM >= 160000
13064 src_rte->perminfoindex = 0;
13066 src_rte->selectedCols = NULL;
13067 src_rte->insertedCols = NULL;
13068 src_rte->updatedCols = NULL;
13069 src_rte->requiredPerms = ACL_SELECT;
13080 ListCell *cell, *prev;
13085 for (cell = list_head(src_rte->eref->colnames); cell != NULL; ) {
13086 if (i == provsql_attno) {
13087 src_rte->eref->colnames =
13092 cell =
my_lnext(src_rte->eref->colnames, cell);
13105 QTW_IGNORE_RT_SUBQUERIES);
13131 FuncExpr *wrap = makeNode(FuncExpr);
13134 wrap->funcretset =
false;
13135 wrap->funcvariadic =
false;
13136 wrap->funcformat = COERCE_EXPLICIT_CALL;
13137 wrap->funccollid = InvalidOid;
13138 wrap->inputcollid = InvalidOid;
13139 wrap->args = list_make1(expr);
13140 wrap->location = -1;
13141 return (Expr *) wrap;
13155 const char *cert) {
13156 FuncExpr *wrap = makeNode(FuncExpr);
13157 Const *ce = makeConst(TEXTOID, -1, DEFAULT_COLLATION_OID, -1,
13158 CStringGetTextDatum(cert),
false,
false);
13161 wrap->funcretset =
false;
13162 wrap->funcvariadic =
false;
13163 wrap->funcformat = COERCE_EXPLICIT_CALL;
13164 wrap->funccollid = InvalidOid;
13165 wrap->inputcollid = DEFAULT_COLLATION_OID;
13166 wrap->args = list_make2(expr, (Expr *) ce);
13167 wrap->location = -1;
13168 return (Expr *) wrap;
13183 FuncExpr *wrap = makeNode(FuncExpr);
13186 wrap->funcretset =
false;
13187 wrap->funcvariadic =
false;
13188 wrap->funcformat = COERCE_EXPLICIT_CALL;
13189 wrap->funccollid = InvalidOid;
13190 wrap->inputcollid = InvalidOid;
13191 wrap->args = list_make2(target, evidence);
13192 wrap->location = -1;
13193 return (Expr *) wrap;
13198#if PG_VERSION_NUM >= 160000
13199 if (r->perminfoindex != 0) {
13200 RTEPermissionInfo *rpi =
13201 list_nth_node(RTEPermissionInfo, q->rteperminfos, r->perminfoindex - 1);
13202 rpi->selectedCols = bms_add_member(
13203 rpi->selectedCols, attno - FirstLowInvalidHeapAttributeNumber);
13206 r->selectedCols = bms_add_member(r->selectedCols,
13207 attno - FirstLowInvalidHeapAttributeNumber);
13214 AttrNumber attno) {
13215 Oid typid; int32 typmod; Oid coll;
13217 get_atttypetypmodcoll(r->relid, attno, &typid, &typmod, &coll);
13218 v = makeVar(relid, attno, typid, typmod, coll, 0);
13226 CoerceViaIO *c = makeNode(CoerceViaIO);
13228 c->resulttype = TEXTOID;
13229 c->resultcollid = DEFAULT_COLLATION_OID;
13230 c->coerceformat = COERCE_IMPLICIT_CAST;
13245 Index relid = prov_var->varno;
13246 RangeTblEntry *r = list_nth_node(RangeTblEntry, q->rtable, relid - 1);
13248 Const *factorc = makeConst(INT4OID, -1, InvalidOid,
sizeof(int32),
13249 Int32GetDatum(m->
factor),
false,
true);
13250 FuncExpr *keyf = makeNode(FuncExpr);
13251 FuncExpr *ann = makeNode(FuncExpr);
13258 secarg = (Expr *) makeConst(TEXTOID, -1, DEFAULT_COLLATION_OID, -1,
13259 CStringGetTextDatum(
"0"),
false,
false);
13265 keyf->funcresulttype = TEXTOID;
13266 keyf->funcretset =
false;
13267 keyf->funcvariadic =
false;
13268 keyf->funcformat = COERCE_EXPLICIT_CALL;
13269 keyf->funccollid = DEFAULT_COLLATION_OID;
13270 keyf->inputcollid = DEFAULT_COLLATION_OID;
13274 keyf->location = -1;
13278 ann->funcretset =
false;
13279 ann->funcvariadic =
false;
13280 ann->funcformat = COERCE_EXPLICIT_CALL;
13281 ann->funccollid = InvalidOid;
13282 ann->inputcollid = DEFAULT_COLLATION_OID;
13283 ann->args = list_make2((Expr *) prov_var, (Expr *) keyf);
13284 ann->location = -1;
13285 return (Expr *) ann;
13297 foreach (lc, prov_atts) {
13298 Node *n = (Node *) lfirst(lc);
13300 Var *pv = (Var *) n;
13301 if (pv->varno >= 1 && (
int) pv->varno <= natoms
13302 && markers[pv->varno - 1].
valid)
13304 &markers[pv->varno - 1]);
13355 if (IsA(node, Var)) {
13356 Var *v = (Var *) node;
13357 if (v->varlevelsup == 0) {
13360 if ((
int) v->varno >= 1 && (
int) v->varno <= c->
sub_rtlen[i]
13362 Var *nv = (Var *) copyObject(v);
13364 return (Node *) nv;
13366 }
else if ((
int) v->varno >= 1 && (
int) v->varno <= c->
N) {
13367 int i = (int) v->varno;
13369 if (v->varattno >= 1 && v->varattno <= c->
sub_tl_n[i]
13370 && c->
sub_tl[i][v->varattno] != NULL) {
13371 Var *base = c->
sub_tl[i][v->varattno];
13372 Var *nv = (Var *) copyObject(base);
13374 nv->varlevelsup = 0;
13375 return (Node *) nv;
13378 Var *nv = (Var *) copyObject(v);
13380 return (Node *) nv;
13384 return (Node *) copyObject(v);
13386 return expression_tree_mutator(node,
flatten_mut, cp);
13393 o->
path = (
int *) palloc(
sizeof(
int));
13403 o->
path = (
int *) palloc(o->
depth *
sizeof(
int));
13405 for (d = 0; d < sub->
depth; d++)
13437 int N = list_length(probe->rtable);
13439 List *new_rtable = NIL;
13440 List *origins_l = NIL;
13441 List *merged_quals = NIL;
13442 bool any_flat =
false, parent_flat = (probe->jointree != NULL);
13448 c.
slot_flat = (
bool *) palloc0((N + 1) *
sizeof(
bool));
13450 c.
sub_newpos = (
int **) palloc0((N + 1) *
sizeof(
int *));
13451 c.
sub_rtlen = (
int *) palloc0((N + 1) *
sizeof(
int));
13452 c.
sub_tl = (Var ***) palloc0((N + 1) *
sizeof(Var **));
13453 c.
sub_tl_n = (
int *) palloc0((N + 1) *
sizeof(
int));
13458 foreach (lc, probe->jointree->fromlist)
13459 if (!IsA((Node *) lfirst(lc), RangeTblRef)) { parent_flat =
false;
break; }
13463 for (i = 1; parent_flat && i <= N; i++) {
13464 RangeTblEntry *rte = list_nth_node(RangeTblEntry, probe->rtable, i - 1);
13473 if (!(rte->rtekind == RTE_SUBQUERY && rte->subquery != NULL && !rte->lateral)) {
13475 new_rtable = lappend(new_rtable, rte);
13480 sq = rte->subquery;
13481 ok = !(sq->commandType != CMD_SELECT
13482 || sq->setOperations || sq->hasAggs || sq->hasWindowFuncs
13483 || sq->groupingSets || sq->groupClause || sq->havingQual
13484 || sq->distinctClause || sq->hasDistinctOn || sq->hasSubLinks
13485 || sq->limitCount || sq->limitOffset || sq->cteList
13486 || sq->jointree == NULL);
13488 foreach (lc2, sq->jointree->fromlist)
13489 if (!IsA((Node *) lfirst(lc2), RangeTblRef)) { ok =
false;
break; }
13500 foreach (lc2, sq->rtable) {
13501 RangeTblEntry *br = (RangeTblEntry *) lfirst(lc2);
13502 if (br->rtekind == RTE_RELATION && br->relkind == RELKIND_VIEW)
13504 else if (br->rtekind == RTE_RELATION) realbase++;
13505 else { ok =
false;
break; }
13507 if (realbase < 1) ok =
false;
13511 foreach (lc2, sq->targetList) {
13512 TargetEntry *te = (TargetEntry *) lfirst(lc2);
13513 if (!te->resjunk && te->resno > maxres) maxres = te->resno;
13515 tl = ok ? (Var **) palloc0((maxres + 1) *
sizeof(Var *)) : NULL;
13517 foreach (lc2, sq->targetList) {
13518 TargetEntry *te = (TargetEntry *) lfirst(lc2);
13521 if (te->resjunk)
continue;
13522 if (!IsA(te->expr, Var)) { ok =
false;
break; }
13523 v = (Var *) te->expr;
13524 if (v->varlevelsup != 0
13525 || (
int) v->varno < 1 || (
int) v->varno > list_length(sq->rtable)) {
13528 br = list_nth_node(RangeTblEntry, sq->rtable, v->varno - 1);
13529 if (!(br->rtekind == RTE_RELATION && br->relkind != RELKIND_VIEW)) {
13540 new_rtable = lappend(new_rtable, rte);
13548 c.
sub_rtlen[i] = list_length(sq->rtable);
13553 foreach (lc2, sq->rtable) {
13554 RangeTblEntry *br = (RangeTblEntry *) lfirst(lc2);
13556 if (br->rtekind == RTE_RELATION && br->relkind != RELKIND_VIEW) {
13558 new_rtable = lappend(new_rtable, copyObject(br));
13563 origins_l = lappend(origins_l,
13564 (sub_origins != NULL && b - 1 < sub_n)
13572 if (parent_flat && any_flat) {
13574 probe->targetList = (List *)
flatten_mut((Node *) probe->targetList, &c);
13575 if (probe->jointree->quals)
13576 merged_quals = lappend(merged_quals,
flatten_mut(probe->jointree->quals, &c));
13578 for (i = 1; i <= N; i++) {
13579 RangeTblEntry *rte;
13581 rte = list_nth_node(RangeTblEntry, probe->rtable, i - 1);
13582 if (rte->subquery->jointree && rte->subquery->jointree->quals) {
13585 lappend(merged_quals,
13586 flatten_mut((Node *) copyObject(rte->subquery->jointree->quals),
13592 probe->rtable = new_rtable;
13595 for (i = 1; i <= newpos; i++) {
13596 RangeTblRef *r = makeNode(RangeTblRef);
13598 fl = lappend(fl, r);
13600 probe->jointree->fromlist = fl;
13602 probe->jointree->quals =
13603 (merged_quals == NIL) ? NULL
13604 : (list_length(merged_quals) == 1) ? (Node *) linitial(merged_quals)
13605 : (Node *) makeBoolExpr(AND_EXPR, merged_quals, -1);
13607 *nflat_out = newpos;
13610 foreach (lc, origins_l)
13619 for (i = 0; i < N; i++) {
13620 origins[i].
depth = 1;
13621 origins[i].
path = (
int *) palloc(
sizeof(
int));
13622 origins[i].
path[0] = i + 1;
13640 Query *q,
char **cert_out) {
13641 bool has_subq =
false, has_group =
false;
13645 int nflat = 0, norigins = 0, N, p;
13650 foreach (lc, q->rtable)
13651 if (((RangeTblEntry *) lfirst(lc))->rtekind == RTE_SUBQUERY) has_subq =
true;
13652#if PG_VERSION_NUM >= 180000
13653 has_group = q->hasGroupRTE;
13659 if (!has_subq && !has_group) {
13662 probe = (Query *) copyObject(q);
13663#if PG_VERSION_NUM >= 180000
13678 N = list_length(q->rtable);
13689 for (p = 0; p < nflat; p++) {
13692 int depth, d, base;
13695 if (!flat[p].valid)
13697 if (origins != NULL) {
13698 if (p >= norigins)
continue;
13699 path = origins[p].
path;
13700 depth = origins[p].
depth;
13702 tmp_path[0] = p + 1;
13707 for (d = 0; d + 1 < depth && cur != NULL; d++) {
13708 int slot = path[d];
13709 RangeTblEntry *rte;
13712 if (slot < 1 || slot > qcur->rtable->length) { cur = NULL;
break; }
13713 rte = list_nth_node(RangeTblEntry, qcur->rtable, slot - 1);
13714 if (rte->rtekind != RTE_SUBQUERY || rte->subquery == NULL) { cur = NULL;
break; }
13715 sublen = list_length(rte->subquery->rtable);
13716 child = cur->
sub[slot - 1];
13717 if (child == NULL) {
13722 cur->
sub[slot - 1] = child;
13725 qcur = rte->subquery;
13729 base = path[depth - 1];
13730 if (base >= 1 && base - 1 < cur->
natoms)
13731 cur->
markers[base - 1] = flat[p];
13746 foreach (lc, arm->targetList) {
13747 TargetEntry *te = (TargetEntry *) lfirst(lc);
13751 e = (Node *) te->expr;
13752 while (e != NULL && IsA(e, RelabelType))
13753 e = (Node *) ((RelabelType *) e)->arg;
13754 if (e == NULL || !IsA(e, Var) || ((Var *) e)->varlevelsup != 0)
13756 heads = lappend(heads, e);
13766 if (!OidIsValid(eqop))
13768 op = makeNode(OpExpr);
13770 op->opfuncid = get_opcode(eqop);
13771 op->opresulttype = BOOLOID;
13772 op->opretset =
false;
13773 op->opcollid = InvalidOid;
13774 op->inputcollid = v1->varcollid;
13775 op->args = list_make2((Var *) copyObject(v1), (Var *) copyObject(v2));
13810 Query *q,
char **cert_out) {
13811 int N = list_length(q->rtable), inner_slot = -1, i, narms, natoms, off;
13812 Query *inner = NULL, *merged;
13814 List *merged_quals = NIL, *fromlist = NIL, *head0 = NIL;
13815 int *arm_off, *arm_base, *arm_real_len;
13817 char *cert_str = NULL;
13818 int mm_natoms = 0, p;
13825 if (q->groupClause == NIL)
13833 if (q->hasAggs || q->havingQual != NULL)
13839 for (i = 0; i < N; i++) {
13840 RangeTblEntry *r = list_nth_node(RangeTblEntry, q->rtable, i);
13841#if PG_VERSION_NUM >= 180000
13842 if (r->rtekind == RTE_GROUP)
13845 if (r->rtekind == RTE_SUBQUERY && r->subquery != NULL
13846 && r->subquery->setOperations != NULL
13847 && IsA(r->subquery->setOperations, SetOperationStmt)
13848 && ((SetOperationStmt *) r->subquery->setOperations)->op == SETOP_UNION
13849 && ((SetOperationStmt *) r->subquery->setOperations)->all) {
13856 if (inner_slot >= 0)
13859 inner = r->subquery;
13866 narms = list_length(inner->rtable);
13870 arm_off = (
int *) palloc((
size_t) narms *
sizeof(
int));
13871 arm_base = (
int *) palloc((
size_t) narms *
sizeof(
int));
13872 arm_real_len = (
int *) palloc((
size_t) narms *
sizeof(
int));
13874 merged = makeNode(Query);
13875 merged->commandType = CMD_SELECT;
13876 merged->rtable = NIL;
13879 foreach (lc, inner->rtable) {
13880 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
13884 if (r->rtekind != RTE_SUBQUERY || r->subquery == NULL)
13886 arm_real_len[i] = list_length(r->subquery->rtable);
13887 arm = (Query *) copyObject(r->subquery);
13888#if PG_VERSION_NUM >= 180000
13889 if (arm->hasGroupRTE)
13892 foreach (lcr, arm->rtable)
13893 if (((RangeTblEntry *) lfirst(lcr))->rtekind != RTE_RELATION)
13896 arm_base[i] = list_length(arm->rtable);
13897 if (arm->jointree && arm->jointree->quals) {
13898 OffsetVarNodes(arm->jointree->quals, off, 0);
13899 merged_quals = lappend(merged_quals, arm->jointree->quals);
13901 OffsetVarNodes((Node *) arm->targetList, off, 0);
13902 merged->rtable = list_concat(merged->rtable, arm->rtable);
13910 if (list_length(heads) != list_length(head0))
13912 forboth (l0, head0, li, heads) {
13916 merged_quals = lappend(merged_quals, eq);
13919 off += arm_base[i];
13926 for (p = 1; p <= natoms; p++) {
13927 RangeTblRef *rr = makeNode(RangeTblRef);
13929 fromlist = lappend(fromlist, rr);
13932 Node *quals = NULL;
13933 if (list_length(merged_quals) == 1)
13934 quals = (Node *) linitial(merged_quals);
13935 else if (merged_quals != NIL)
13936 quals = (Node *) makeBoolExpr(AND_EXPR, merged_quals, -1);
13937 merged->jointree = makeFromExpr(fromlist, quals);
13943 foreach (lh, head0)
13944 tl = lappend(tl, makeTargetEntry((Expr *) copyObject(lfirst(lh)),
13945 (AttrNumber) resno++, NULL,
false));
13946 merged->targetList = tl;
13951 if (mm == NULL || mm_natoms != natoms)
13955 ctx_inner->
natoms = narms;
13958 for (i = 0; i < narms; i++) {
13961 arm_ctx->
natoms = arm_real_len[i];
13964 for (loc = 0; loc < arm_base[i]; loc++)
13965 arm_ctx->
markers[loc] = mm[arm_off[i] + loc];
13966 ctx_inner->
sub[i] = arm_ctx;
13973 ctx->
sub[inner_slot] = ctx_inner;
13976 *cert_out = cert_str;
14009 TargetEntry *value = NULL;
14012 foreach (lc, sub->targetList) {
14013 TargetEntry *te = (TargetEntry *)lfirst(lc);
14023 kept = list_make1(value);
14024 foreach (lc, sub->targetList) {
14025 TargetEntry *te = (TargetEntry *)lfirst(lc);
14026 if (te != value && te->resjunk)
14027 kept = lappend(kept, te);
14030 ((TargetEntry *)lfirst(lc))->resno = ++n;
14031 sub->targetList = kept;
14038 if (IsA(node, SubLink)) {
14039 SubLink *sl = (SubLink *)node;
14040 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
14041 IsA(sl->subselect, Query) &&
14043 (Query *)sl->subselect)) {
14044 bool *removed = NULL;
14046 &removed,
false,
false,
false, NULL);
14048 sl->subselect = (Node *)processed;
14054 return expression_tree_walker((Node *) sl->testexpr,
14057 if (IsA(node, Query))
14140 if (IsA(node, Var)) {
14141 Var *v = (Var *)node;
14142 if ((
int)v->varlevelsup == c->
sublevels_up && v->varattno <= 0 &&
14147 if (IsA(node, Query)) {
14165 if (IsA(node, Var)) {
14166 Var *v = (Var *)node;
14167 if ((
int)v->varlevelsup == c->
sublevels_up && v->varattno > 0 &&
14168 bms_is_member(v->varno, c->
flattened)) {
14169 RangeTblEntry *rte = rt_fetch(v->varno, c->
rtable);
14171 (Node *)copyObject(list_nth(rte->joinaliasvars, v->varattno - 1));
14176 return (Node *)copyObject(v);
14178 if (IsA(node, Query)) {
14183 return (Node *)res;
14194 Bitmapset **joins) {
14197 if (IsA(jt, RangeTblRef)) {
14198 *refs = lappend(*refs, jt);
14201 if (IsA(jt, JoinExpr)) {
14202 JoinExpr *j = (JoinExpr *)jt;
14203 if (j->jointype != JOIN_INNER || j->alias != NULL)
14209 *quals = lappend(*quals, j->quals);
14210 *joins = bms_add_member(*joins, j->rtindex);
14233 if (IsA(node, Var)) {
14234 Var *v = (Var *)copyObject(node);
14236 if ((
int)v->varno >= 1 && (
int)v->varno <= c->
old_size &&
14239#if PG_VERSION_NUM >= 130000
14240 if ((
int)v->varnosyn >= 1 && (
int)v->varnosyn <= c->
old_size) {
14242 v->varnosyn = (Index)c->
old_to_new[v->varnosyn];
14245 v->varattnosyn = 0;
14252 if (IsA(node, RangeTblRef)) {
14253 RangeTblRef *r = (RangeTblRef *)copyObject(node);
14259 if (IsA(node, JoinExpr)) {
14260 JoinExpr *j = (JoinExpr *)expression_tree_mutator(node,
renumber_rte_mut, cx);
14266 if (IsA(node, Query)) {
14271 return (Node *)res;
14293 Bitmapset *flattened = NULL;
14294 bool changed =
false;
14298 if (q->commandType != CMD_SELECT || q->jointree == NULL)
14303 foreach (lc, q->jointree->fromlist) {
14304 Node *item = (Node *)lfirst(lc);
14305 List *refs = NIL, *jquals = NIL;
14306 Bitmapset *joins = NULL;
14307 if (IsA(item, JoinExpr) &&
14309 flattened = bms_union(flattened, joins);
14316 actx.
rtable = q->rtable;
14336 List *newfrom = NIL, *conjs = NIL;
14337 foreach (lc, q->jointree->fromlist) {
14338 Node *item = (Node *)lfirst(lc);
14339 List *refs = NIL, *jquals = NIL;
14340 Bitmapset *joins = NULL;
14342 if (IsA(item, JoinExpr) &&
14344 newfrom = list_concat(newfrom, refs);
14345 foreach (qc, jquals)
14347 list_concat(conjs, make_ands_implicit((Expr *)lfirst(qc)));
14349 newfrom = lappend(newfrom, item);
14352 if (q->jointree->quals)
14354 list_concat(conjs, make_ands_implicit((Expr *)q->jointree->quals));
14355 q->jointree->fromlist = newfrom;
14356 q->jointree->quals =
14357 (conjs == NIL) ? NULL : (Node *)make_ands_explicit(conjs);
14365 int old_size = list_length(q->rtable);
14366 int next = 1, i = 1;
14367 List *new_rtable = NIL;
14369 rctx.
old_to_new = (
int *)palloc0((old_size + 1) *
sizeof(
int));
14370 foreach (lc, q->rtable) {
14371 if (!bms_is_member(i, flattened)) {
14373 new_rtable = lappend(new_rtable, lfirst(lc));
14377 q->rtable = new_rtable;
14391 if (IsA(node, Query)) {
14392 Query *sub = (Query *)node;
14400 bool **removed,
bool wrap_root,
bool top_level,
14401 bool in_boolean_rewrite,
14404 bool has_union =
false;
14405 bool has_difference =
false;
14406 bool supported =
true;
14407 bool group_by_rewrite =
false;
14409 int **columns = NULL;
14410 int columns_len = 0;
14412 char *inv_cert = NULL;
14414 List *given_evidence = NIL;
14416 elog_node_display(NOTICE,
"ProvSQL: Before query rewriting", q,
true);
14464 if (q->rtable == NULL) {
14475 if (rv_cmps != NIL) {
14477 RangeTblEntry *values_rte;
14481 if (list_length(rv_cmps) == 1) {
14485 FuncExpr *times = makeNode(FuncExpr);
14486 ArrayExpr *array = makeNode(ArrayExpr);
14489 times->funcvariadic =
true;
14490 times->location = -1;
14493 array->elements = rv_cmps;
14494 array->location = -1;
14495 times->args = list_make1(array);
14508 values_rte = makeNode(RangeTblEntry);
14509 values_rte->rtekind = RTE_VALUES;
14510 values_rte->values_lists = list_make1(list_make1(
provenance));
14511 values_rte->coltypes = list_make1_oid(constants->
OID_TYPE_UUID);
14512 values_rte->coltypmods = list_make1_int(-1);
14513 values_rte->colcollations = list_make1_oid(InvalidOid);
14514 values_rte->eref = makeAlias(
14517 values_rte->inh =
false;
14518 values_rte->inFromCl =
true;
14519#if PG_VERSION_NUM < 160000
14520 values_rte->requiredPerms = 0;
14522 q->rtable = list_make1(values_rte);
14524 rtr = makeNode(RangeTblRef);
14526 if (q->jointree == NULL) {
14527 q->jointree = makeNode(FromExpr);
14529 q->jointree->fromlist = list_make1(rtr);
14531 v = makeVar(1, 1, constants->
OID_TYPE_UUID, -1, InvalidOid, 0);
14540 TargetEntry *te = makeTargetEntry(
14541 (Expr *)copyObject(v),
14542 list_length(q->targetList) + 1,
14545 q->targetList = lappend(q->targetList, te);
14595 Bitmapset *removed_sortgrouprefs = NULL;
14597 if (q->targetList) {
14598 removed_sortgrouprefs =
14600 if (removed_sortgrouprefs != NULL)
14602 if (q->setOperations)
14617 if (given_evidence != NIL &&
14618 (q->hasAggs || q->groupClause || q->groupingSets || q->havingQual ||
14619 q->distinctClause || q->setOperations || q->hasWindowFuncs))
14621 "provsql.given (whole-tuple output conditioning) is supported only in "
14622 "a plain per-row SELECT, not in an aggregated / grouped / DISTINCT / "
14623 "set-operation query; condition the individual tokens with the binary "
14624 "| operator instead");
14628 if (q->setOperations) {
14632 SetOperationStmt *stmt = (SetOperationStmt *)q->setOperations;
14638 foreach (lc_rte, q->rtable) {
14639 RangeTblEntry *rte = (RangeTblEntry *)lfirst(lc_rte);
14640 if (rte->rtekind == RTE_SUBQUERY && rte->subquery &&
14641 rte->subquery->hasAggs)
14643 "aggregate results not supported");
14646 return process_query(constants, q, removed, wrap_root, top_level,
14647 in_boolean_rewrite, inv_ctx);
14654 return process_query(constants, rewritten, removed, wrap_root, top_level,
14655 in_boolean_rewrite, inv_ctx);
14664 return process_query(constants, rewritten, removed, wrap_root,
14665 top_level, in_boolean_rewrite, inv_ctx);
14673 AttrNumber join_attno;
14680 return process_query(constants, rewritten, removed, wrap_root,
14681 top_level, in_boolean_rewrite, inv_ctx);
14709 return process_query(constants, rewritten, removed,
true, top_level,
14722 if (inv_ctx != NULL) {
14726 local_inv_ctx = inv_ctx;
14743 if (local_inv_ctx == NULL)
14762 top_level, local_inv_ctx);
14768 if (local_inv_ctx != NULL && local_inv_ctx->
markers != NULL)
14772 if (prov_atts == NIL) {
14779 if (q->jointree && q->jointree->quals &&
14781 FuncExpr *one_expr = makeNode(FuncExpr);
14784 one_expr->args = NIL;
14785 one_expr->location = -1;
14786 prov_atts = list_make1(one_expr);
14804 bool has_direct =
false;
14806 if (has_direct || nested == NIL) {
14807 provsql_error(
"Subqueries (EXISTS, IN, scalar subquery) not supported");
14811 "scalar subquery nested in an expression is not tracked; its data is "
14812 "treated as certain and the result keeps only the outer provenance");
14819 if (supported && q->distinctClause)
14822 if (supported && q->setOperations) {
14823 SetOperationStmt *stmt = (SetOperationStmt *)q->setOperations;
14825 if (stmt->op == SETOP_UNION) {
14828 }
else if (stmt->op == SETOP_EXCEPT) {
14831 has_difference =
true;
14833 provsql_error(
"Set operations other than UNION and EXCEPT not "
14839 if (supported && q->groupClause &&
14841 group_by_rewrite =
true;
14844 if (supported && q->groupingSets) {
14845 if (q->groupClause || list_length(q->groupingSets) > 1 ||
14846 ((GroupingSet *)linitial(q->groupingSets))->kind !=
14847 GROUPING_SET_EMPTY) {
14848 provsql_error(
"GROUPING SETS, CUBE, and ROLLUP not supported");
14852 group_by_rewrite =
true;
14862 columns_len = q->rtable->length;
14863 columns = (
int **)palloc0(columns_len *
sizeof(
int *));
14877 if (q->hasWindowFuncs)
14879 "tracked per input row only, and the windowed "
14880 "computation is treated as an opaque scalar");
14900 if (rv_cmps != NIL && !has_union && !has_difference) {
14901 prov_atts = list_concat(prov_atts, rv_cmps);
14910 constants, q, prov_atts,
14925 foreach (lc_sort, q->sortClause) {
14926 SortGroupClause *sort = (SortGroupClause *)lfirst(lc_sort);
14928 foreach (lc_te, q->targetList) {
14929 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
14930 if (sort->tleSortGroupRef == te->ressortgroupref) {
14932 provsql_error(
"ORDER BY on the result of an aggregate function is "
14945 constants, q, prov_atts, q->hasAggs, group_by_rewrite,
14947 nbcols, wrap_root, in_boolean_rewrite, inv_cert);
14952 if (rv_cmps != NIL) {
14953 FuncExpr *times = makeNode(FuncExpr);
14954 ArrayExpr *array = makeNode(ArrayExpr);
14957 times->funcvariadic =
true;
14958 times->location = -1;
14961 array->elements = lcons(
provenance, rv_cmps);
14962 array->location = -1;
14963 times->args = list_make1(array);
14976 foreach (lc_ev, given_evidence)
14983 if (has_difference)
14990 for (i = 0; columns != NULL && i < (unsigned)columns_len; ++i) {
14997 elog_node_display(NOTICE,
"ProvSQL: After query rewriting", q,
true);
15027 if (IsA(node, Var)) {
15028 Var *v = (Var *)node;
15029 if (v->varno == ctx->
src_rteid && v->varlevelsup == 0 &&
15030 v->varattno >= 1 && v->varattno <= ctx->
natts) {
15031 ctx->
types[v->varattno - 1] = v->vartype;
15032 ctx->
typmods[v->varattno - 1] = v->vartypmod;
15065 ctx.
natts = list_length(subquery->targetList);
15066 if (ctx.
natts == 0)
15068 ctx.
types = (Oid *)palloc0(
sizeof(Oid) * ctx.
natts);
15069 ctx.
typmods = (int32 *)palloc(
sizeof(int32) * ctx.
natts);
15070 for (i = 0; i < ctx.
natts; ++i)
15075 foreach (lc, subquery->targetList) {
15076 TargetEntry *te = (TargetEntry *)lfirst(lc);
15080 if (te->resjunk || te->resno < 1 || te->resno > ctx.
natts)
15082 want = ctx.
types[te->resno - 1];
15083 if (!OidIsValid(want))
15085 have = exprType((Node *)te->expr);
15088 coerced = coerce_to_target_type(NULL, (Node *)te->expr, have, want,
15090 COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST,
15092 if (coerced != NULL)
15093 te->expr = (Expr *)coerced;
15112 Index src_rteid = 0;
15113 RangeTblEntry *src_rte = NULL;
15114 RangeTblEntry *tgt_rte;
15115 AttrNumber provsql_attno = 0;
15116 TargetEntry *provsql_te = NULL;
15117 bool provsql_te_is_new =
false;
15120 foreach (lc, q->rtable) {
15121 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
15123 if (r->rtekind == RTE_SUBQUERY && r->subquery &&
15130 if (src_rte == NULL)
15140 bool *removed = NULL;
15141 Query *new_subquery =
15142 process_query(constants, src_rte->subquery, &removed,
false,
false,
false,
15144 if (new_subquery == NULL)
15146 src_rte->subquery = new_subquery;
15154 tgt_rte = list_nth_node(RangeTblEntry, q->rtable, q->resultRelation - 1);
15155 if (tgt_rte->rtekind == RTE_RELATION) {
15156 AttrNumber attid = 1;
15157 foreach (lc, tgt_rte->eref->colnames) {
15159 get_atttype(tgt_rte->relid, attid) == constants->
OID_TYPE_UUID)
15160 provsql_attno = attid;
15165 if (provsql_attno == 0) {
15172 "tables: source provenance is not propagated "
15173 "to inserted rows");
15178 foreach (lc, q->targetList) {
15179 TargetEntry *te = (TargetEntry *)lfirst(lc);
15180 if (te->resno == provsql_attno &&
15187 if (provsql_te == NULL) {
15192 provsql_te = makeNode(TargetEntry);
15193 provsql_te->resno = provsql_attno;
15195 provsql_te_is_new =
true;
15200 AttrNumber src_provsql_attno = 0;
15202 foreach (lc, src_rte->subquery->targetList) {
15203 TargetEntry *te = (TargetEntry *)lfirst(lc);
15206 src_provsql_attno = te->resno;
15211 if (src_provsql_attno == 0)
15216 Var *v = makeNode(Var);
15217 v->varno = src_rteid;
15218 v->varattno = src_provsql_attno;
15221 v->varcollid = InvalidOid;
15223 provsql_te->expr = (Expr *)v;
15228 if (provsql_te_is_new)
15229 q->targetList = lappend(q->targetList, provsql_te);
15232 src_rte->eref->colnames = lappend(src_rte->eref->colnames,
15262 if (IsA(node, Query)) {
15263 Query *q = (Query *)node;
15265 foreach (lc, q->targetList) {
15266 TargetEntry *te = (TargetEntry *)lfirst(lc);
15267 if (te->resjunk || te->resname == NULL ||
15270 if (IsA(te->expr, Var) &&
15306#
if PG_VERSION_NUM >= 130000
15307 const char *query_string,
15310 ParamListInfo boundParams
15311#
if PG_VERSION_NUM >= 190000
15320 if (q->commandType == CMD_INSERT && q->rtable &&
provsql_active) {
15322 if (constants.
ok) {
15324 provsql_error(
"a subquery over a provenance-tracked relation cannot be "
15325 "used as a scalar subquery / IN / EXISTS expression; put "
15326 "it in the FROM clause instead");
15330 }
else if (q->commandType == CMD_UPDATE && q->rtable &&
provsql_active) {
15338 }
else if (q->commandType == CMD_SELECT) {
15353 provsql_error(
"a subquery over a provenance-tracked relation cannot be "
15354 "used as a scalar subquery / IN / EXISTS expression; put "
15355 "it in the FROM clause instead");
15368 && q->rtable != NIL) {
15376 bool *removed = NULL;
15387 provsql_error(
"a query may not define a column named \"%s\" by hand; "
15388 "ProvSQL manages the provenance column itself",
15391#if PG_VERSION_NUM >= 150000
15394 pg_get_querydef(q,
true));
15400 new_query =
process_query(&constants, q, &removed,
false,
true,
false,
15405 (
double)(clock() - begin) / CLOCKS_PER_SEC);
15407 if (new_query != NULL)
15410#if PG_VERSION_NUM >= 150000
15413 pg_get_querydef(q,
true));
15422#
if PG_VERSION_NUM >= 130000
15425 cursorOptions, boundParams
15426#
if PG_VERSION_NUM >= 190000
15431 return standard_planner(q,
15432#
if PG_VERSION_NUM >= 130000
15435 cursorOptions, boundParams
15436#
if PG_VERSION_NUM >= 190000
15460 standard_ExecutorStart(queryDesc, eflags);
15471#if PG_VERSION_NUM >= 130000
15477 standard_ExecutorEnd(queryDesc);
15493 standard_ExecutorEnd(queryDesc);
15562 CreateTableAsStmt *stmt;
15566 AttrNumber prov_resno = InvalidAttrNumber;
15567 Oid source_relid = InvalidOid;
15569 Bitmapset *ancestor_bms = NULL;
15576 if (parsetree == NULL || !IsA(parsetree, CreateTableAsStmt))
15578 stmt = (CreateTableAsStmt *) parsetree;
15579 if (stmt->query == NULL || !IsA(stmt->query, Query))
15581 qry = (Query *) stmt->query;
15582 if (qry->commandType != CMD_SELECT)
15595 foreach (lc, qry->targetList) {
15596 TargetEntry *te = (TargetEntry *) lfirst(lc);
15597 Node *e = (Node *) te->expr;
15599 RangeTblEntry *rte;
15600 AttrNumber prov_attno;
15604 while (e != NULL && IsA(e, RelabelType))
15605 e = (Node *) ((RelabelType *) e)->arg;
15606 if (e == NULL || !IsA(e, Var))
15609 if (v->varlevelsup != 0)
15611 if (v->varno < 1 || (
int) v->varno > list_length(qry->rtable))
15613 rte = (RangeTblEntry *) list_nth(qry->rtable, v->varno - 1);
15614 if (rte->rtekind != RTE_RELATION)
15617 if (prov_attno == InvalidAttrNumber || v->varattno != prov_attno)
15623 prov_resno = te->resno;
15624 source_relid = rte->relid;
15627 if (prov_resno == InvalidAttrNumber) {
15638 Oid src_relid = lfirst_oid(lc);
15642 for (uint16 i = 0; i < src_n; ++i)
15643 ancestor_bms = bms_add_member(ancestor_bms, (
int) src_ancestors[i]);
15645 ancestor_bms = bms_add_member(ancestor_bms, (
int) src_relid);
15652 while ((bms_member = bms_next_member(ancestor_bms, bms_member)) >= 0) {
15657 bms_free(ancestor_bms);
15660 cap->
ancestors[ancestor_n++] = (Oid) bms_member;
15662 bms_free(ancestor_bms);
15705 CreateTableAsStmt *stmt;
15707 AttrNumber prov_attno;
15709 uint16 eff_block_key_n = 0;
15712 Datum block_key_datum;
15713 Datum ancestors_datum;
15714 Datum *block_key_elems;
15715 Datum *ancestor_elems;
15716 ArrayType *block_key_arr;
15717 ArrayType *ancestors_arr;
15718 const char *nspname;
15719 const char *relname;
15720 StringInfoData trigger_sql;
15724 stmt = (CreateTableAsStmt *) parsetree;
15726 new_relid = RangeVarGetRelid(stmt->into->rel, NoLock,
true);
15727 if (new_relid == InvalidOid)
15735 if (prov_attno == InvalidAttrNumber)
15737 if (get_atttype(new_relid, prov_attno) != UUIDOID)
15752 bool found =
false;
15754 TargetEntry *te = (TargetEntry *) lfirst(lc);
15755 Node *e = (Node *) te->expr;
15757 RangeTblEntry *rte;
15760 while (e != NULL && IsA(e, RelabelType))
15761 e = (Node *) ((RelabelType *) e)->arg;
15762 if (e == NULL || !IsA(e, Var))
15765 if (v->varlevelsup != 0)
15768 || (
int) v->varno > list_length(cap->
inner_query->rtable))
15770 rte = (RangeTblEntry *)
15771 list_nth(cap->
inner_query->rtable, v->varno - 1);
15772 if (rte->rtekind != RTE_RELATION)
15775 && v->varattno == src_attno) {
15780 eff_block_key[eff_block_key_n++] = te->resno;
15792 eff_block_key_n = 0;
15801 if (eff_block_key_n == 0) {
15802 block_key_arr = construct_empty_array(INT2OID);
15804 block_key_elems = palloc(eff_block_key_n *
sizeof(Datum));
15805 for (uint16 i = 0; i < eff_block_key_n; ++i)
15806 block_key_elems[i] = Int16GetDatum(eff_block_key[i]);
15807 block_key_arr = construct_array(block_key_elems, eff_block_key_n,
15808 INT2OID, 2,
true,
's');
15809 pfree(block_key_elems);
15811 block_key_datum = PointerGetDatum(block_key_arr);
15813 ObjectIdGetDatum(new_relid),
15818 ancestors_arr = construct_empty_array(OIDOID);
15820 ancestor_elems = palloc(cap->
ancestor_n *
sizeof(Datum));
15821 for (uint16 i = 0; i < cap->
ancestor_n; ++i)
15822 ancestor_elems[i] = ObjectIdGetDatum(cap->
ancestors[i]);
15823 ancestors_arr = construct_array(ancestor_elems, cap->
ancestor_n,
15824 OIDOID,
sizeof(Oid),
true,
'i');
15825 pfree(ancestor_elems);
15827 ancestors_datum = PointerGetDatum(ancestors_arr);
15829 ObjectIdGetDatum(new_relid),
15846#if PG_VERSION_NUM >= 140000
15847 if (stmt->objtype == OBJECT_MATVIEW)
15849 if (stmt->relkind == OBJECT_MATVIEW)
15853 nspname = get_namespace_name(get_rel_namespace(new_relid));
15854 relname = get_rel_name(new_relid);
15855 if (nspname == NULL || relname == NULL)
15857 initStringInfo(&trigger_sql);
15858 appendStringInfo(&trigger_sql,
15859 "CREATE TRIGGER provenance_guard "
15860 "BEFORE INSERT OR UPDATE OF provsql ON %s.%s "
15865 "FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()",
15866 quote_identifier(nspname), quote_identifier(relname));
15867 if (SPI_connect() != SPI_OK_CONNECT)
15869 if (SPI_exec(trigger_sql.data, 0) != SPI_OK_UTILITY)
15870 provsql_error(
"CTAS lineage hook: failed to install provenance_guard "
15871 "on %s.%s", nspname, relname);
15873 pfree(trigger_sql.data);
15877 PlannedStmt *pstmt,
15878 const char *queryString,
15879#
if PG_VERSION_NUM >= 140000
15882 ProcessUtilityContext context,
15883 ParamListInfo params,
15884 QueryEnvironment *queryEnv,
15885 DestReceiver *dest,
15886#
if PG_VERSION_NUM >= 130000
15887 QueryCompletion *qc
15889 char *completionTag
15892 Node *parsetree = pstmt ? pstmt->utilityStmt : NULL;
15899#
if PG_VERSION_NUM >= 140000
15902 context, params, queryEnv, dest,
15903#
if PG_VERSION_NUM >= 130000
15910 standard_ProcessUtility(pstmt, queryString,
15911#
if PG_VERSION_NUM >= 140000
15914 context, params, queryEnv, dest,
15915#
if PG_VERSION_NUM >= 130000
15936#ifndef PROVSQL_INPROCESS_STORE
15944 if (!process_shared_preload_libraries_in_progress)
15945 provsql_error(
"provsql needs to be added to the shared_preload_libraries "
15946 "configuration variable");
15949 DefineCustomBoolVariable(
"provsql.active",
15950 "Should ProvSQL track provenance?",
15951 "1 is standard ProvSQL behavior, 0 means provsql attributes will be dropped.",
15959 DefineCustomEnumVariable(
"provsql.provenance",
15960 "Provenance class tracked and assumed by the rewriter.",
15961 "Declares, for the session, the most specific "
15962 "class of provenance semantics the circuits "
15963 "must remain faithful for; constructions are "
15964 "licensed accordingly, from the most general "
15965 "to the most specialised: 'where' adds "
15966 "where-provenance tracking (equality and "
15967 "projection gates) on top of universal "
15968 "semiring provenance; 'semiring' (the "
15969 "default) tracks universal semiring "
15970 "provenance; 'absorptive' additionally lets "
15971 "recursive queries on cyclic data stop at "
15972 "the absorptive value fixpoint, tagging "
15973 "their tokens so non-absorptive semirings "
15974 "refuse them; 'boolean' (which implies "
15975 "'absorptive') additionally enables the "
15976 "Boolean-only machinery -- the safe-query "
15977 "read-once rewrite, the bounded-treewidth "
15978 "reachability route, Boolean circuit "
15979 "simplifications -- whose outputs only "
15980 "preserve the Boolean function of the "
15981 "lineage and are tagged as such.",
15990 DefineCustomBoolVariable(
"provsql.update_provenance",
15991 "Should ProvSQL track update provenance?",
15992 "1 turns update provenance on, 0 off.",
16000 DefineCustomBoolVariable(
"provsql.aggtoken_text_as_uuid",
16001 "Output agg_token cells as the underlying UUID "
16002 "instead of \"value (*)\".",
16003 "Off by default for psql-friendly output. UI "
16004 "layers (notably ProvSQL Studio) flip this on "
16005 "per session so aggregate cells expose the "
16006 "circuit root UUID for click-through; the "
16007 "display value is recovered via "
16008 "provsql.agg_token_value_text(uuid).",
16016 DefineCustomIntVariable(
"provsql.verbose_level",
16017 "Level of verbosity for ProvSQL informational and debug messages",
16018 "0 for quiet (default), 1-9 for informational messages, 10-100 for debug information.",
16028 DefineCustomStringVariable(
"provsql.tool_search_path",
16029 "Directories prepended to PATH when ProvSQL spawns external tools (superuser-only).",
16030 "Colon-separated list of directories searched before the server's PATH "
16031 "when locating d4, c2d, minic2d, dsharp, weightmc, or graph-easy. "
16032 "Empty (default) means rely on the server's PATH alone. "
16033 "Restricted to superusers (PGC_SUSET): it controls which directories the "
16034 "postgres OS user searches for executables, so a non-privileged role must "
16035 "not be able to redirect it to an attacker-controlled binary.",
16043 DefineCustomStringVariable(
"provsql.fallback_compiler",
16044 "Compiler used by makeDD's final fallback when both "
16045 "interpretAsDD and tree-decomposition fail.",
16046 "Name of the external compiler invoked by "
16047 "BooleanCircuit::makeDD after interpretAsDD raises "
16048 "(non-independent or non-NNF circuit) and the "
16049 "tree-decomposition builder raises (treewidth above "
16050 "the supported bound). Accepts any value supported "
16051 "by BooleanCircuit::compilation: d4, d4v2, c2d, "
16052 "minic2d, dsharp, panini-obdd, panini-obdd-and, "
16053 "panini-decdnnf. Default: d4.",
16061 DefineCustomStringVariable(
"provsql.kcmcp_server",
16062 "Launch command for the managed KCMCP knowledge-compiler server.",
16063 "Shell command the supervisor background worker runs to start a "
16064 "warm KCMCP server (see the KC server protocol). The literal "
16065 "{endpoint} is replaced by a Unix-socket path the worker picks "
16066 "and publishes for the in-extension client to reach (a registry "
16067 "record of kind 'kcmcp' with endpoint 'managed' uses it). {endpoint} "
16068 "already carries the scheme (e.g. unix:/path). Empty (default) "
16069 "launches no server. Example: 'tdkc --kcmcp {endpoint}'. "
16070 "PGC_SIGHUP (config file / ALTER SYSTEM + reload): it runs an "
16071 "arbitrary command as the postgres OS user, so like "
16072 "provsql.tool_search_path it is not settable per session.",
16080 DefineCustomStringVariable(
"provsql.last_eval_method",
16081 "Probability evaluation method(s) used by the most "
16082 "recent probability_evaluate call.",
16083 "Set automatically after each probability_evaluate "
16084 "call to the method that produced the result "
16085 "(comma-separated and deduplicated across calls in "
16086 "the session). Useful to see which strategy the "
16087 "default auto-selection settled on.",
16095 DefineCustomBoolVariable(
"provsql.simplify_on_load",
16096 "Apply universal cmp-resolution passes when "
16097 "loading a provenance circuit.",
16098 "When on (default), every GenericCircuit returned "
16099 "by getGenericCircuit goes through RangeCheck "
16100 "(and any future universal pass): comparators "
16101 "decidable to certain Boolean values become "
16102 "Bernoulli gate_input gates with probability 0 "
16103 "or 1, transparent to every downstream consumer "
16104 "(semiring evaluators, MC, view_circuit, PROV "
16105 "export). Set off to inspect raw circuit "
16106 "structure (e.g. when debugging gate-creation "
16120 DefineCustomBoolVariable(
"provsql.hybrid_evaluation",
16121 "Run the hybrid-evaluator simplifier and "
16122 "island decomposer inside probability_evaluate. "
16124 "When on (default), probability_evaluate runs "
16125 "the HybridEvaluator peephole simplifier "
16126 "between RangeCheck and AnalyticEvaluator and "
16127 "the per-cmp MC island decomposer after "
16128 "AnalyticEvaluator. Off bypasses both and lets "
16129 "unresolved comparators fall through to "
16130 "whole-circuit MC. End users have no reason "
16131 "to flip this; it exists for developer A/B "
16132 "testing against the unfolded path and as a "
16133 "bisection knob if a closure rule turns out "
16134 "to be unsound on some workload.",
16138 GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE,
16151 DefineCustomBoolVariable(
"provsql.cmp_probability_evaluation",
16152 "Run closed-form / analytic probability "
16153 "evaluators for gate_cmps inside "
16154 "probability_evaluate. Debug only.",
16155 "When on (default), probability_evaluate "
16156 "runs pre-passes that recognise specific "
16157 "gate_cmp shapes (currently HAVING COUNT(*) "
16158 "op C over distinct gate_input leaves) and "
16159 "replace each cmp with a Bernoulli "
16160 "gate_input carrying the closed-form "
16161 "probability, bypassing the DNF that "
16162 "provsql_having's enumerate_valid_worlds "
16163 "would otherwise emit. Off forces the cmp "
16164 "to fall through to that enumeration path. "
16165 "Future MIN / MAX / SUM probability "
16166 "evaluators will gate on the same flag. "
16167 "End users have no reason to flip this; it "
16168 "exists for developer A/B testing and as a "
16169 "bisection escape valve.",
16173 GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE,
16183 DefineCustomBoolVariable(
"provsql.inversion_free",
16184 "Use the inversion-free structured-d-DNNF "
16185 "probability path when available.",
16186 "When on (default), probability_evaluate, on a "
16187 "query whose provenance root carries an "
16188 "inversion-free tractability certificate, tries the "
16189 "structured-d-DNNF builder after the read-once "
16190 "independent evaluator and before the "
16191 "tree-decomposition / external-compiler fallback. "
16192 "Off disables only this automatic insertion; the "
16193 "explicit probability_evaluate(token, "
16194 "'inversion-free') method always runs and errors "
16195 "without a certificate. The path is gated on the "
16196 "certificate, attached only to certified queries, "
16197 "so on is safe; off serves developer A/B testing.",
16201 GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE,
16205 DefineCustomBoolVariable(
"provsql.classify_top_level",
16206 "Emit a NOTICE classifying each top-level SELECT.",
16207 "When on, every top-level SELECT that "
16208 "touches a relation triggers a NOTICE of "
16209 "the form `ProvSQL: query result is "
16210 "<KIND> (sources: ...)` where <KIND> is "
16211 "TID, BID, or OPAQUE under the existing "
16212 "provsql_table_kind taxonomy and the "
16213 "sources list names the provenance-"
16214 "tracked base relations the query touches. "
16215 "Read-only : the classifier does not "
16216 "rewrite the query. Studio reads the "
16217 "NOTICE to label query results with their "
16226 DefineCustomIntVariable(
"provsql.monte_carlo_seed",
16227 "Seed for the Monte Carlo sampler.",
16228 "-1 (default) seeds from std::random_device for "
16229 "non-deterministic sampling. Any other value "
16230 "(including 0) is used as a literal seed for "
16231 "std::mt19937_64, making "
16232 "probability_evaluate(..., 'monte-carlo', n) "
16233 "reproducible across runs and across the Bernoulli "
16234 "and continuous (gate_rv) sampling paths.",
16244 DefineCustomIntVariable(
"provsql.rv_mc_samples",
16245 "Default sample count for analytical-evaluator MC fallbacks.",
16246 "Used when an analytical evaluator (Expectation, "
16247 "future hybrid evaluator, etc.) cannot decompose a "
16248 "sub-circuit and needs to fall back to Monte Carlo. "
16249 "Default 10000. Set to 0 to disable the fallback "
16250 "entirely: callers raise an exception rather than "
16251 "sampling, which is useful when only analytical "
16252 "answers are acceptable. Unrelated to "
16253 "probability_evaluate(..., 'monte-carlo', n) where "
16254 "the sample count is an explicit argument.",
16265 DefineCustomRealVariable(
"provsql.ess_warn_fraction",
16266 "Effective-sample-size warning threshold for likelihood weighting.",
16267 "Latent-variable posterior inference draws latents from "
16268 "the prior and weights them by the observed leaves' "
16269 "densities. When the posterior effective sample size "
16270 "(Sum(w)^2 / Sum(w^2)) falls below this fraction of the "
16271 "accepted draws, a warning is emitted: the weights are "
16272 "degenerating (raise provsql.rv_mc_samples, or the model "
16273 "has many observations per latent). Default 0.1; set to 0 "
16274 "to silence the warning.",
16285 DefineCustomIntVariable(
"provsql.dtree_max_subproblems",
16286 "Hard cap on d-tree subproblems before it bails (0 = off).",
16287 "Debug / safety knob for the d-tree speculative-execution "
16288 "budget. The cost chooser already budgets the d-tree at the "
16289 "next-best method's estimated cost; when this is > 0 it adds "
16290 "a fixed hard cap on the number of d-tree subproblems, after "
16291 "which the method throws and the chooser escalates to the "
16292 "next method. 0 leaves only the automatic budget.",
16303 DefineCustomIntVariable(
"provsql.joint_max_treewidth",
16304 "Maximum joint treewidth the joint-width UCQ "
16305 "compiler attempts.",
16306 "The joint-width UCQ compiler "
16307 "(ucq_joint_evaluate) evaluates an arbitrary UCQ -- "
16308 "including queries that are #P-hard under the "
16309 "Dalvi-Suciu dichotomy -- exactly, tractably when "
16310 "the joint treewidth of the data and its "
16311 "correlation structure is bounded. Above this "
16312 "bound the path declines (the degeneracy screen or "
16313 "the min-fill build raises), and the caller falls "
16314 "back to the standard probability ladder. Default "
16315 "10 (the tree-decomposition compiler's own cap).",
16325 DefineCustomIntVariable(
"provsql.joint_max_states",
16326 "Per-bag DP state-count cap of the joint-width UCQ "
16328 "The joint-width UCQ compiler caps the number of "
16329 "dynamic-programming states at any decomposition "
16330 "node; exceeding it raises and the caller falls "
16331 "back to the ladder. This cap, not the static "
16332 "enumerating-variable count, is the true safety "
16333 "net: the realised state count is governed by data "
16334 "sparsity and the absorbing satisfied-state "
16335 "collapse, typically far below the a-priori bound. "
16347 DefineCustomBoolVariable(
"provsql.joint_width",
16348 "Recognise unsafe UCQs at planner time and route "
16349 "their existence provenance through the "
16350 "joint-width compiler (debug-only switch).",
16351 "On by default. When provsql.provenance = "
16352 "'boolean', a conjunctive query the safe-query "
16353 "rewriter declined -- an unsafe / #P-hard UCQ -- "
16354 "whose existence is being formed (DISTINCT / GROUP "
16355 "BY) is recognised and its provenance replaced by "
16356 "the joint-width compiler's certified d-D (exact "
16357 "and tractable when the joint treewidth of the data "
16358 "and its correlation structure is bounded). Turn "
16359 "off only to compare against the general lineage "
16369 DefineCustomBoolVariable(
"provsql.mobius",
16370 "Try the safe-UCQ Möbius-inversion route before the "
16371 "joint-width compiler (debug-only switch).",
16372 "On by default. The last missing exact route of the "
16373 "Dalvi-Suciu dichotomy: a UCQ safe only because the "
16374 "#P-hard terms of its inclusion-exclusion expansion "
16375 "carry a zero Möbius value on the CNF lattice and "
16376 "cancel (canonical witness QW / q9). Shares the "
16377 "joint-width descriptor but has PRECEDENCE over it: a "
16378 "guaranteed-PTIME exact route for its class (TID, "
16379 "self-join-free, safe), it is tried first and "
16380 "short-circuits past the joint-width compiler on "
16381 "success. The joint-width compiler runs only on a "
16382 "Möbius decline (correlated inputs, self-joins, "
16383 "unsafe shape); on its decline too the normal "
16384 "provenance is the fallback, so the query never "
16385 "fails. Turn off only to compare against the "
16386 "joint-width / general lineage for debugging.",
16395 DefineCustomIntVariable(
"provsql.mobius_max_gates",
16396 "Data-cost cap of the safe-UCQ Möbius-inversion "
16398 "The Möbius route is PTIME in its class but its "
16399 "lifted-inference recursion is O(|D|^k) in the data, "
16400 "k the safe query's level (number of nested "
16401 "independent-projections) -- supra-linear, and the "
16402 "degree grows with the query. To keep it safe to "
16403 "leave on by default with precedence, it declines "
16404 "(falling through to the joint-width compiler / the "
16405 "ladder) once its compile has built more than this "
16406 "many gates, so a high-level safe query on large data "
16407 "never out-costs the general pipeline. Default "
16419 DefineCustomIntVariable(
"provsql.mobius_max_cnf",
16420 "Query-cost cap of the safe-UCQ Möbius-inversion "
16422 "The route walks the inclusion-exclusion lattice of "
16423 "the CNF of each sentence it meets, which has 2^M "
16424 "elements for M conjuncts, and declines above this "
16425 "cap. The bound is on the QUERY, not the data: only "
16426 "a very large union, or the ranking / shattering "
16427 "normalisation of a self-join, pushes M up. "
16428 "Default 8; 0 disables the cap.",
16440 EmitWarningsOnPlaceholders(
"provsql");
16447#ifdef PROVSQL_INPROCESS_STORE
16451 provsql_inproc_init();
16452#elif (PG_VERSION_NUM >= 150000)
16460#ifndef PROVSQL_INPROCESS_STORE
16467#ifndef PROVSQL_INPROCESS_STORE
#define PROVSQL_TABLE_INFO_MAX_BLOCK_KEY
Cap on the number of block-key columns recorded per relation.
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.
bool provsql_classify_top_level
Backing storage for the provsql.classify_top_level GUC.
void provsql_classify_emit_notice(const ProvSQLClassification *c)
Render the result of provsql_classify_query as a NOTICE.
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.
List * list_insert_nth(List *list, int pos, void *datum)
Insert datum at position pos in list (PG < 13 backport).
PostgreSQL cross-version compatibility shims for ProvSQL.
#define F_ARRAY_AGG_ANYNONARRAY
OID of the array_agg(anynonarray) aggregate (pre-PG 14).
static List * my_list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Version-agnostic wrapper around list_delete_cell().
static ListCell * my_lnext(const List *l, const ListCell *c)
Version-agnostic wrapper around lnext().
#define TYPALIGN_INT
Alignment codes for the array routines (construct_array / deconstruct_array).
#define F_COUNT_
OID of count() aggregate function (pre-PG 14).
static FuncCandidateList FuncnameGetCandidatesCompat(List *names, int nargs, List *argnames, bool expand_variadic, bool expand_defaults, bool include_out_arguments, bool missing_ok)
Version-agnostic wrapper around FuncnameGetCandidates().
#define F_COUNT_ANY
OID of count(*) / count(any) aggregate function (pre-PG 14).
char * provsql_joint_width_descriptor(const constants_t *constants, Query *q, bool *all_existential, List **head_var_idx, List **head_exprs)
Build the joint-width descriptor for a recognised UCQ.
Planner-time recognition of unsafe UCQs for the joint-width compiler.
void RegisterProvSQLKCMCPWorker(void)
Register the supervisor background worker that launches and supervises the managed KCMCP server; call...
int provsql_mobius_max_gates
Data-cost cap of the Möbius route: it declines (falling through to joint-width / the ladder) once its...
Datum provenance(PG_FUNCTION_ARGS)
Error stub for provsql.provenance() on untracked tables.
static void transform_distinct_into_group_by(Query *q)
Convert a SELECT DISTINCT into an equivalent GROUP BY.
static void check_unlowered_outer_joins(const constants_t *constants, Query *q, Node *n)
Refuse outer joins that survived lower_outer_joins with a provenance-tracked relation on a null-padde...
static Expr * make_aggregation_expression(const constants_t *constants, Aggref *agg_ref, List *prov_atts, semiring_operation op, bool is_scalar)
Build the provenance expression for a single aggregate function.
static bool sublink_classify_walker(Node *node, void *cx)
Walker classifying each tracked SubLink of a query as either a still-unsupported direct form or an ar...
static void collect_direct_qual_sublinks(Node *node, List **out)
Collect SubLink nodes sitting in a "direct", decorrelatable position: a target-list entry that is the...
static bool contains_agg_walker(Node *node, contains_agg_ctx *ctx)
static const char * provsql_ctas_kind_label(provsql_table_kind k)
Map provsql_table_kind to its textual label (set_table_info accepts text).
static Node * cast_agg_token_to_type(Node *arg, Oid target_type, const constants_t *constants)
Wrap an agg_token expression in a cast to target_type.
static void remove_provenance_attribute_groupref(Query *q, const Bitmapset *removed_sortgrouprefs)
Remove sort/group references that belonged to removed provenance columns.
static Node * rewrite_probability_event_mutator(Node *node, void *data)
Mutator: lift the RV surface that can appear in the target list.
static bool contains_aggref_walker(Node *node, void *found)
Walker for expr_contains_aggref.
static bool normalize_inner_joins_walker(Node *node, void *cx)
Walker: apply normalize_inner_joins to every nested Query – sublink subselects, subquery RTEs,...
static qual_class classify_qual(Expr *expr, const constants_t *constants)
Classify expr along the qual_class axis.
static Node * lift_rv_event_mutator(Node *node, void *data)
Mutator: lift any random_variable comparison event to its token.
static FuncExpr * having_Expr_to_provenance_cmp(Expr *expr, const constants_t *constants, bool negated)
Dispatch a HAVING sub-expression to the appropriate converter.
static void maybe_cast_agg_token_args(List *args, Oid parent_funcid, const constants_t *constants)
Cast provenance_aggregate arguments of an operator or function when the formal parameter type require...
Datum set_ancestors(PG_FUNCTION_ARGS)
PostgreSQL-callable wrapper for setTableAncestry() over the IPC pipe.
static bool transform_except_into_join(const constants_t *constants, Query *q)
Rewrite an EXCEPT query into a LEFT JOIN with monus provenance.
bool provsql_where_provenance
Global variable that indicates if where-provenance support has been activated through the provsql....
bool provsql_absorptive_provenance
Derived flag: the session's provenance class is 'absorptive' or 'boolean' – licenses constructions so...
static void normalize_inner_joins(Query *q)
Canonicalise explicit inner joins in q's FROM to the comma-join form: each all-inner JoinExpr fromlis...
static void oj_neutralize_orphan_arm(RangeTblEntry *rel)
Neutralise an outer-join arm RTE left orphaned after the lowering so get_provenance_attributes does n...
static bool oj_tl_sublink_in_arith(Node *node, SubLink *sl)
Is SubLink sl reachable from node through arithmetic only?
static bool normalize_quantified_aggregate_sublinks(const constants_t *constants, Query *q)
Normalize quantified comparisons over a single bare-aggregate body into plain scalar comparisons.
static bool has_provenance_walker(Node *node, void *data)
static Expr * wrap_in_cond(const constants_t *constants, Expr *target, Expr *evidence)
Wrap target in a provsql.cond(uuid, uuid) FuncExpr conditioning it on evidence.
static bool has_rv_or_provenance_call(Node *node, void *data)
Tree walker that detects any provenance-bearing relation or provenance() call.
int provsql_verbose
Verbosity level; controlled by the provsql.verbose_level GUC.
static bool oj_refs_join_index(Query *q, Index join_idx)
True if any outer Var references the join RTE directly (USING / whole-row / alias....
static Expr * build_mobius_answer_expr(const constants_t *constants, const char *desc, List *head_var_idx, List *head_exprs, Expr *fallback)
Build the per-answer ucq_mobius_provenance_answer(...) call, identical in shape to build_joint_width_...
static Node * extract_quantified_corr(SubLink *sl, bool *antijoin, bool neg, const Query *outerq, bool *guarded)
Build the per-row correlation for a quantified sublink (IN / op ANY / op ALL), setting *antijoin.
static bool sublink_over_tracked_walker(Node *node, void *cx)
Walker: set found if a SubLink whose subselect (transitively) involves a provenance-tracked relation ...
static bool rewrite_array_sublinks(const constants_t *constants, Query *q)
Rewrite a top-level ARRAY(SELECT Q.col FROM Q WHERE corr) target-list entry into the aggregate body (...
static Aggref * oj_make_count_star(void)
A fresh count(*) Aggref (returns int8).
static bool expr_has_probabilistic_cmp(Node *node, void *data)
Walker: does node contain a probabilistic (random_variable or aggregate) comparison?
static Node * normalize_bool_agg_having(Node *n)
static bool aggtoken_walker(Node *node, void *data)
Tree walker that detects any Var of type agg_token.
static Query * oj_build_diff(const constants_t *constants, Query *outer, RangeTblEntry *R, RangeTblEntry *S, Index R_idx, Index S_idx, oj_cols *Rc, oj_cols *Sc, Node *theta, bool keep_left)
Build the difference subquery for the kept side of an outer join: "SELECT X.cols FROM X EXCEPT ALL SE...
static FuncExpr * make_regular_indicator(const constants_t *constants, Expr *expr, bool negated)
Build the deterministic indicator gate for an ordinary (regular) comparison: regular_indicator(cond) ...
static Node * rewrite_cond_predicate_mutator(Node *node, void *data)
Mutator: rewrite "X | (predicate)" into the carrier's cond.
static List * provsql_inert_subselects
Walker (this query level only): true if an EXPR_SUBLINK whose body is a decorrelatable value subquery...
static bool collect_source_var_types(Node *node, void *cx)
Walker: record the column types the INSERT expects from its source.
static bool oj_is_arith_opexpr(Node *node)
Is node a binary/unary +,-,*,/ operator expression?
static bool check_selection_on_aggregate(OpExpr *op, const constants_t *constants)
Check whether op is a supported comparison on an aggregate result.
static Expr * build_joint_width_provenance_expr(const constants_t *constants, const char *desc, Expr *fallback)
Build the ucq_joint_provenance(descriptor) call substituted for a recognised unsafe UCQ's existence p...
void _PG_init(void)
Extension initialization – called once when the shared library is loaded.
bool provsql_simplify_on_load
Run universal cmp-resolution passes when getGenericCircuit returns; controlled by the provsql....
static List * inv_free_arm_head_vars(Query *arm)
The output (head) columns of a UNION arm as plain base Var\ s.
static bool oj_rte_has_provsql(const constants_t *constants, RangeTblEntry *rel)
True if rel contributes provenance: a base relation with a provsql UUID column, or a subquery over tr...
static FuncExpr * having_BoolExpr_to_provenance(BoolExpr *be, const constants_t *constants, bool negated)
Convert a Boolean combination of HAVING comparisons into a provenance_times / provenance_plus gate ex...
static Node * oj_renum_mut(Node *node, void *cx)
static bool is_target_agg_var(Node *node, aggregation_type_mutator_context *context)
Check if a Var matches the target aggregate column.
static RangeTblEntry * oj_make_subquery_rte(Query *sub)
Wrap a constructed Query as an RTE_SUBQUERY, building its eref->colnames from the (non-junk) target l...
static bool expr_provably_not_null(Node *e, const Query *q, Index levelsup)
Conservative provably-not-NULL test for the sublink lift.
static bool has_aggtoken(Node *node, const constants_t *constants)
Return true if node contains a Var of type agg_token.
static List * classify_remaining_sublinks(const constants_t *constants, Query *q, bool *has_direct)
Partition q's remaining tracked sublinks into unsupported-direct vs arithmetic-nested.
static int rv_cmp_index(const constants_t *constants, Oid funcoid)
Test whether funcoid is one of the random_variable_* comparison procedures, and if so return its Comp...
static void process_inert_fetches(const constants_t *constants, Query *q)
int provsql_mobius_max_cnf
Query-cost cap of the Möbius route: it declines when a sentence's CNF has more than this many conjunc...
static FuncExpr * having_NullTest_to_provenance(NullTest *nt, const constants_t *constants, bool negated)
Convert a NullTest on an aggregate (agg IS [NOT] NULL) into a provenance expression.
static bool cte_reference_walker(Node *node, void *context)
Walker: does the tree contain an RTE_CTE reference to a CTE of the given name?
static bool oj_limit_count_is_one(Node *limitCount)
Is limitCount the literal 1?
#define PROVSQL_JOIN_ALIAS
Sentinel eref alias marking join RTEs that ProvSQL itself constructs (the EXCEPT antijoin,...
static void rewrite_probability_events(const constants_t *constants, Query *q)
Lift RV-comparison events in q's target list into their tokens.
static void replace_provenance_function_by_expression(const constants_t *constants, Query *q, Expr *provsql)
Replace every explicit provenance() call in q with provsql.
static FuncExpr * having_null_filtered_plus(const constants_t *constants, Aggref *base_arr, Node *V, Node *K, NullTestType filter)
Build "⊕(array_agg(K) FILTER (WHERE V IS [NOT] NULL))" – the per-row provenance ⊕ over just the value...
static Node * reduce_varattno_mutator(Node *node, void *ctx)
Tree-mutator callback that adjusts Var attribute numbers.
static Node * oj_outer_remap(Node *node, void *cx)
bool provsql_inversion_free
Insert the inversion-free structured-d-DNNF path into the default probability chain (after independen...
static void provsql_ProcessUtility_capture(Node *parsetree, ProvSQLCtasCapture *cap)
Decide whether parsetree is a CTAS that should trigger the ancestry hook, and if so populate cap with...
static bool inert_fetch_sublink_walker(Node *node, void *data)
Walker: set found if an inert provenance()-fetch SubLink is present in this query's own clauses (not ...
double provsql_ess_warn_fraction
Effective-sample-size warning threshold for likelihood weighting: warn when the posterior ESS falls b...
static Query * oj_build_uncorrelated_from_subquery(const constants_t *constants, Query *body)
Build the derived single-row aggregate D for an UNcorrelated scalar subquery body,...
static Expr * build_joint_width_answer_expr(const constants_t *constants, const char *desc, List *head_var_idx, List *head_exprs, Expr *fallback)
Build the per-answer ucq_joint_provenance_answer(...) call for a recognised non-Boolean UCQ (head var...
static Node * oj_replace_sublink_mut(Node *node, void *cx)
Replace one specific SubLink node with repl, in place.
static Node * oj_param_repl_mut(Node *node, void *cx)
Replace every PARAM_SUBLINK with paramid by replacement.
static bool case_is_agg_carrier(CaseExpr *ce, const constants_t *constants)
static Node * build_rv_case(CaseExpr *ce, const constants_t *constants)
Lower an RV-typed searched CASE into a rv_case(...) call.
char * provsql_last_eval_method
Last probability evaluation method(s) used; exposed via provsql.last_eval_method.
static bool check_expr_on_rv(Expr *expr, const constants_t *constants)
Test whether expr is a Boolean combination of only random_variable comparisons (no other leaves allow...
PG_MODULE_MAGIC
Required PostgreSQL extension magic block.
static void wrap_inversion_free_markers(const constants_t *constants, Query *q, List *prov_atts, const InvFreeMarker *markers, int natoms)
Replace each certified atom's provenance Var in prov_atts with its per-input-marker-wrapped form (in ...
static void insert_agg_token_casts(const constants_t *constants, Query *q)
Walk query and insert agg_token casts where needed.
Datum set_table_info(PG_FUNCTION_ARGS)
Forward declaration of the C SQL entry points.
static Query * build_inner_for_distinct_key(Query *q, Expr *key_expr, List *groupby_tes)
Build the inner GROUP-BY subquery for one AGG(DISTINCT key).
static bool oj_rtables_coalescible(List *rta, List *rtb)
Can two scalar-subquery bodies share a single decorrelating LEFT JOIN?
static Expr * wrap_random_variable_uuid(Node *operand, const constants_t *constants)
Wrap an expression returning random_variable in a binary-coercible cast to uuid.
static bool having_entails_group_existence(Expr *expr, const constants_t *constants, bool negated)
Whether a lifted HAVING predicate already entails that the group exists.
bool provsql_mobius
Try the safe-UCQ Möbius-inversion route (a guaranteed-PTIME exact route for its class) BEFORE the joi...
int provsql_rv_mc_samples
Default sample count for analytical-evaluator MC fallbacks; 0 disables fallback (callers raise instea...
int provsql_dtree_max_subproblems
Debug/safety hard cap on d-tree subproblems before it bails (0 = off; the chooser auto-budgets at the...
static bool oj_sublink_scan_walker(Node *node, void *cx)
static Node * add_to_havingQual(Node *havingQual, Expr *expr)
Append expr to havingQual with an AND, creating one if needed.
static void fix_type_of_aggregation_result(const constants_t *constants, Query *q, Index rteid, List *targetList)
Retypes aggregation-result Vars in q from UUID to agg_token.
static Aggref * build_rv_sum_aggref(const constants_t *constants, Oid aggfnoid, Expr *arg)
Build an Aggref for an RV-summing aggregate over arg.
static Expr * wrap_in_assume_boolean(const constants_t *constants, Expr *expr)
Wrap expr in a provsql.assume_boolean FuncExpr.
static void hide_provsql_colname(RangeTblEntry *rel)
Rename the provsql column in rel's eref so a later get_provenance_attributes pass does not re-detect ...
static void provsql_executor_end(QueryDesc *queryDesc)
char * provsql_kcmcp_server
Launch command for the managed KCMCP server (with a {endpoint} placeholder); controlled by the provsq...
static FlatAtomOrigin * flatten_spj_subqueries(Query *probe, int *nflat_out)
In place, inline every SPJ subquery/view of probe into its base relations, flattening to one conjunct...
static bool is_inert_subselect(Query *q)
Is q a recorded inert provenance()-fetch subselect?
static void process_set_operation_union(const constants_t *constants, SetOperationStmt *stmt, Query *q)
Recursively annotate a UNION tree with the provenance UUID type.
static Query * rewrite_join_agg_token(Query *q, const constants_t *constants, Index rteid, AttrNumber join_attno)
Replace the source relation of an agg_token JOIN with an explode-style subquery.
static bool oj_joinref_walker(Node *node, void *cx)
static bool having_lift_walker(Node *node, void *data)
Walker for needs_having_lift: detect any operand shape that the HAVING-lift rewriter (having_OpExpr_t...
static Node * wrap_agg_token_with_cast(FuncExpr *prov_agg, const constants_t *constants)
Wrap a provenance_aggregate FuncExpr with a cast to the original aggregate return type.
static void oj_build_coltype_lists(oj_cols *Rc, oj_cols *Sc, List **types, List **typmods, List **collations)
Build the column-type lists (R-then-S, user columns only) shared by every set-operation node of the r...
static InvFreeMarkerCtx * build_inversion_free_ctx(const constants_t *constants, Query *q, char **cert_out)
Build the inversion-free marker context for top-level query q.
static void replace_aggregations_by_provenance_aggregate(const constants_t *constants, Query *q, List *prov_atts, semiring_operation op)
Replace every Aggref in q with a provenance-aware aggregate.
static Var * make_provenance_attribute(const constants_t *constants, Query *q, RangeTblEntry *r, Index relid, AttrNumber attid)
Build a Var node that references the provenance column of a relation.
static void inline_ctes_in_rtable(List *rtable, List *cteList, List **lowered, List *kept)
Inline CTE references as subqueries within a query.
static bool query_defines_handmade_provsql(Node *node, void *cx)
Walker: true if any Query in the tree defines a provsql column by hand.
static bool predicate_subselect_decorrelatable(const constants_t *constants, Query *sub, bool corr_supplied)
Is sub a subselect that the predicate-sublink rewrite can turn into a correlated "SELECT count(*) FRO...
bool provsql_joint_width
Recognise unsafe UCQs at planner time and route their existence provenance through the joint-width co...
static void rewrite_dml_rv_surface(const constants_t *constants, Query *q)
Lower the RV surface in the values a data-modifying statement supplies directly.
static bool oj_wrap_body_with_match_ind(const constants_t *constants, Query *sub)
Wrap a NULL-guarded antijoin body into a derived subquery D carrying a constant match-indicator colum...
static void provsql_executor_start(QueryDesc *queryDesc, int eflags)
static bool query_references_cte(Query *q, const char *name)
Does q (at any depth) reference a CTE named name?
static void remove_provenance_attribute_setoperations(Query *q, bool *removed)
Strip the provenance column's type info from a set-operation node.
static void add_to_select(Query *q, Expr *provenance)
Append the provenance expression to q's target list.
void _PG_fini(void)
Extension teardown – restores the planner and shmem hooks.
static Node * provenance_mutator(Node *node, void *ctx)
Tree-mutator that replaces provenance() calls with the actual provenance expression.
provsql_provenance_class_t
Values of the provsql.provenance enum GUC, from most general to most specialised.
@ PROVSQL_PROVENANCE_WHERE
Universal semiring provenance plus where-provenance gates.
@ PROVSQL_PROVENANCE_BOOLEAN
Boolean-only machinery licensed (tagged); implies absorptive.
@ PROVSQL_PROVENANCE_SEMIRING
Universal semiring provenance (default).
@ PROVSQL_PROVENANCE_ABSORPTIVE
Absorptive-semiring constructions licensed (tagged).
static Node * oj_sl_replace_mut(Node *node, void *cx)
static bool join_wholerow_walker(Node *node, void *cx)
Walker: does any Var reference a dissolved join RTE as a whole row (varattno <= 0)?
static void restore_insert_source_types(Query *q, Index src_rteid, Query *subquery)
Coerce the rewritten source SELECT back to the types the INSERT expects.
static Node * rewrite_agg_case_mutator(Node *node, void *context)
static Node * aggregation_type_mutator(Node *node, void *ctx)
Tree-mutator that retypes a specific Var to agg_token.
int provsql_monte_carlo_seed
Seed for the Monte Carlo sampler; -1 means non-deterministic (std::random_device); controlled by the ...
static bool oj_sub_bodies_coalescible(Query *a, Query *b)
static void provsql_ProcessUtility_apply(Node *parsetree, ProvSQLCtasCapture *cap)
Apply cap to the freshly-created relation stmt->into->rel.
static bool inner_join_collect(Node *jt, List **refs, List **quals, Bitmapset **joins)
Recursively collect an all-inner join tree's leaf RangeTblRefs, ON quals, and dissolved RTE_JOIN rtin...
static Node * replace_having_distinct_mutator(Node *node, void *ctx)
Mutator that replaces each AGG(DISTINCT) Aggref in a HAVING clause with Var(next_rtindex++,...
static List * migrate_probabilistic_quals(const constants_t *constants, Query *q)
Unified WHERE classifier – routes each top-level conjunct to the right evaluation site in a single pa...
static bool collect_having_distinct_walker(Node *node, void *ctx)
Walker that collects AGG(DISTINCT) Aggrefs from an expression.
static bool decorr_value_sublink_walker(Node *node, void *data)
static List * get_provenance_attributes(const constants_t *constants, Query *q, bool in_boolean_rewrite, bool top_level, const InvFreeMarkerCtx *inv_ctx)
Collect all provenance Var nodes reachable from q's range table.
static void cast_agg_token_in_list(ListCell *lc, insert_agg_token_casts_context *ctx)
Wrap an agg_token Var in a cast to its original type, in place.
bool provsql_cmp_probability_evaluation
Run closed-form / analytic probability evaluators for gate_cmps inside probability_evaluate (currentl...
static Query * oj_build_antijoin(const constants_t *constants, Query *outer, RangeTblEntry *R, RangeTblEntry *S, Index R_idx, Index S_idx, oj_cols *Rc, oj_cols *Sc, Node *theta, bool keep_left)
Build a null-padded antijoin arm in R-then-S column order.
static Expr * build_inversion_free_marker(const constants_t *constants, Query *q, Var *prov_var, const InvFreeMarker *m)
Wrap an atom's provenance Var in the inversion-free per-input order marker: annotate(prov,...
static bool query_has_inert_fetch(const constants_t *constants, Query *q)
Does q's own target list / jointree / HAVING contain an inert provenance()-fetch SubLink?
static Expr * wrap_in_annotate(const constants_t *constants, Expr *expr, const char *cert)
Wrap expr in a provsql.annotate(uuid, text) FuncExpr carrying cert.
static const struct config_enum_entry provsql_provenance_options[]
Option table of the provsql.provenance GUC.
static void rewrite_cond_predicates(const constants_t *constants, Query *q)
Rewrite every "X | (predicate)" in q's own clauses.
static Node * cast_agg_token_mutator(Node *node, void *ctx)
Tree-mutator that casts provenance_aggregate results back to the original aggregate return type where...
char * provsql_tool_search_path
Colon-separated directory list prepended to PATH when invoking external tools (d4,...
static bool move_uncorrelated_sublinks_to_from(const constants_t *constants, Query *q)
Move uncorrelated scalar subqueries that are direct target-list entries into a cross-joined derived a...
static OpExpr * normalize_agg_comparison(OpExpr *cmp, const constants_t *constants)
Fold constant arithmetic over an aggregate into the comparison threshold.
static Node * push_arith_into_agg_mutator(Node *node, void *ctx)
Tree-mutator applying try_push_into_aggref bottom-up.
static Query * push_agg_nulltest_into_subquery(Query *q, const constants_t *constants)
Push IS [NOT] NULL on a subquery's aggregate down into that subquery's HAVING.
static void mark_col_selected(Query *q, RangeTblEntry *r, AttrNumber attno)
Mark column attno of RTE r as selected (read permission).
static Query * process_query(const constants_t *constants, Query *q, bool **removed, bool wrap_root, bool top_level, bool in_boolean_rewrite, const InvFreeMarkerCtx *inv_ctx)
static Query * rewrite_agg_distinct(Query *q, const constants_t *constants)
Rewrite every AGG(DISTINCT key) in q using independent subqueries.
static bool node_is_agg_token(Node *n, const constants_t *constants)
static bool rewrite_uncorrelated_antijoin(const constants_t *constants, Query *q)
Rewrite an uncorrelated WHERE predicate that is satisfied by the empty group – NOT EXISTS,...
bool provsql_interrupted
Global variable that becomes true if this particular backend received an interrupt signal.
static void keep_only_provenance_output(Query *sub)
Make a processed inert subselect return exactly its provenance token as a single column.
static bool calls_provenance_walker(Node *node, void *data)
Walker: true if node (descending through nested queries) contains an explicit provenance() call.
#define PROVSQL_MATCH_IND_COLNAME
Column name of the constant match indicator added by oj_wrap_body_with_match_ind.
static Expr * combine_prov_atts(const constants_t *constants, List *prov_atts, semiring_operation op)
Build the per-row provenance token for an aggregate rewrite.
static Node * try_push_into_aggref(OpExpr *op, const constants_t *constants)
Push distributive constant arithmetic into an aggregate's argument.
bool provsql_boolean_provenance
Derived flag: the session's provenance class is 'boolean' – enables the Boolean-only machinery (safe-...
int provsql_joint_max_states
Per-bag DP state-count cap of the joint-width UCQ compiler (the true safety net); provsql....
static Node * agg_arm_to_uuid(Node *arm, const constants_t *constants)
static FuncExpr * rv_BoolExpr_to_provenance(BoolExpr *be, const constants_t *constants, bool negated)
Convert a Boolean combination of RV comparisons into a provenance_times / provenance_plus expression.
static Node * build_agg_case(CaseExpr *ce, const constants_t *constants)
static FuncExpr * predicate_to_condition_gate(Expr *expr, const constants_t *constants, bool negated)
Convert a Boolean predicate into a provenance condition gate.
static bool provenance_in_sublink_walker(Node *node, void *data)
Walker: true if a SubLink subselect calls provenance().
static bool decorrelate_scalar_sublinks(const constants_t *constants, Query *q)
Decorrelate a single top-level scalar subquery into a LEFT JOIN.
static RangeTblEntry * oj_copy_rel(Query *outer, Query *sub, RangeTblEntry *orig)
Copy an outer-join arm RTE into the range table of subquery sub.
static Node * join_alias_resolve_mut(Node *node, void *cx)
Mutator: replace every Var referencing a dissolved join RTE by its joinaliasvars expression – resolve...
static bool oj_zero_satisfies(Oid opno, Const *c)
Does 0 satisfy the int8 comparison "0 <opno> c"?
static Expr * add_eq_from_Quals_to_Expr(const constants_t *constants, Node *quals, Expr *result, int **columns)
Walk a join-condition or WHERE quals node and add eq gates for every equality it contains.
static Query * rewrite_non_all_into_external_group_by(Query *q)
Wrap a non-ALL set operation in an outer GROUP BY query.
static Query * oj_build_union(const constants_t *constants, Query *outer, RangeTblEntry *R, RangeTblEntry *S, Index R_idx, Index S_idx, oj_cols *Rc, oj_cols *Sc, Node *theta, JoinType jointype)
Build the UNION-ALL of the matched arm and the outer join's antijoin arm(s): the full outer-join rela...
char * provsql_fallback_compiler
Compiler used by BooleanCircuit::makeDD as the final fallback after interpretAsDD and tree-decomposit...
static PlannedStmt * provsql_planner(Query *q, int cursorOptions, ParamListInfo boundParams)
PostgreSQL planner hook – entry point for provenance rewriting.
static bool oj_wrap_body_from(const constants_t *constants, Query *sub)
Collapse a multi-table scalar-subquery body FROM into one derived cross-product subquery D,...
static ExecutorStart_hook_type prev_ExecutorStart
static bool provsql_active
true while ProvSQL query rewriting is enabled
static bool oj_contains_sublink_walker(Node *node, void *cx)
Walker: true if the subtree contains the specific SubLink cx.
static bool provenance_function_in_group_by(const constants_t *constants, Query *q)
Check whether a provenance() call appears in the GROUP BY list.
static Expr * combine_safe_routes(const constants_t *constants, Expr *mobius_call, Expr *joint_call, Expr *lineage)
Combine the Möbius and joint-width routes under Möbius precedence.
static void provsql_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
static bool move_uncorrelated_where_predicates(const constants_t *constants, Query *q)
Handle UNcorrelated EXISTS and uncorrelated aggregate comparisons in WHERE by cross-joining a HAVING-...
static OpExpr * inv_free_make_eq(Var *v1, Var *v2)
Build the equality qual v1 = v2, or NULL if the types have no = operator.
static Bitmapset * remove_provenance_attributes_select(const constants_t *constants, Query *q, bool **removed)
Strip provenance UUID columns from q's SELECT list.
static Node * oj_decorr_var_mut(Node *node, void *cx)
static void provsql_provenance_assign_hook(int newval, void *extra)
Assign hook of provsql.provenance: refresh the derived per-class flags.
static bool is_supported_bool_agg(Oid aggfnoid)
static bool oj_uncorrelated_body_over_tracked(const constants_t *constants, Query *sub)
Is sub an uncorrelated clean SELECT over tracked base relations (a comma-join is fine)?
static Expr * wrap_mobius_or_null(const constants_t *constants, Expr *mobius_call)
Wrap a Möbius call in mobius_or_null(...): the token if it roots a gate_mobius (a Möbius success),...
static bool lower_outer_joins(const constants_t *constants, Query *q)
Lower a top-level outer JOIN of two base relations into the UNION-ALL of its matched and null-padded ...
static bool oj_body_has_tracked_relation(const constants_t *constants, Query *body)
Does the body's range table reach at least one provenance-tracked relation?
static Expr * add_eq_from_OpExpr_to_Expr(const constants_t *constants, OpExpr *fromOpExpr, Expr *toExpr, int **columns)
Wrap toExpr in a provenance_eq gate if fromOpExpr is an equality between two tracked columns.
static Node * build_count_predicate(Query *subselect, Node *extra_corr, bool antijoin)
Turn a predicate subselect into the boolean "(SELECT count(*) FROM Q WHERE corr) >= 1" (semijoi...
static bool oj_wrap_outer_from(const constants_t *constants, Query *q, SubLink *sl, bool in_where)
Wrap a non-single-relation outer FROM into a derived subquery R' so a scalar subquery can be decorrel...
static InvFreeMarkerCtx * build_inversion_free_union_ctx(const constants_t *constants, Query *q, char **cert_out)
Build the inversion-free marker context for a set-semantics UNION of inversion-free branches (the ful...
static OpExpr * oj_count_distinct_cmp(Expr *valexpr, const char *opstr, int64 n)
Build "count(DISTINCT v) <op> n" -- the at-most-one-DISTINCT-value gate of a "SELECT DISTINCT v" body...
static FuncExpr * rv_Expr_to_provenance(Expr *expr, const constants_t *constants, bool negated)
Dispatch a WHERE sub-expression to the appropriate RV converter.
static Query * oj_build_join_query(const constants_t *constants, Query *outer, RangeTblEntry *R, RangeTblEntry *S, Index R_idx, Index S_idx, oj_cols *Rc, oj_cols *Sc, Node *theta, bool select_r, bool select_s)
Build the inner-join scan subquery "SELECT [R.cols][, S.cols] FROM R JOIN S ON θ".
static planner_hook_type prev_planner
Previous planner hook (chained).
static void normalize_distinct_into_group_by(Query *q)
Normalise a supported SELECT DISTINCT into a GROUP BY.
static bool check_boolexpr_on_aggregate(BoolExpr *be, const constants_t *constants)
Check whether every leaf of a Boolean expression is a supported comparison on an aggregate result.
static bool jointree_arm_has_tracked(const constants_t *constants, Query *q, Node *n)
Walker: does the jointree fragment n reference a provenance-tracked RTE of q?
static void process_insert_select(const constants_t *constants, Query *q)
Propagate provenance through INSERT ... SELECT.
static FlatAtomOrigin * flat_origin1(int slot)
A depth-1 origin path [slot].
static bool subselect_is_pure_provenance_fetch(const constants_t *constants, Query *sub)
Whether sub's sole non-junk output is a bare provenance() call.
static bool join_qual_has_agg_token_walker(Node *node, join_qual_agg_token_ctx *ctx)
static bool sublink_is_inert(SubLink *sl)
Does sl wrap a recorded inert provenance()-fetch subselect?
static bool push_one_agg_nulltest(NullTest *nt, agg_nulltest_ctx *ctx)
Move one IS [NOT] NULL conjunct into its subquery's HAVING.
static bool expr_contains_rv_cmp(Node *node, const constants_t *constants)
Test whether an Expr (sub-)tree contains any RV comparison.
static Oid get_agg_token_orig_type(Var *v, insert_agg_token_casts_context *ctx)
Look up the original aggregate return type for an agg_token Var.
static Aggref * oj_make_aggref(Oid aggfnoid, Oid aggtype, Oid argtype, Expr *arg)
Build an Aggref for a single-argument aggregate.
static void cast_agg_token_args(List *args, insert_agg_token_casts_context *ctx)
Wrap any agg_token Vars in an argument list.
static void oj_collect_cols(const constants_t *constants, RangeTblEntry *rel, oj_cols *out)
Collect the user columns (skipping provsql and dropped columns) of an outer-join arm: a base relation...
static bool const_as_double(Node *n, double *out)
Numeric value of a (possibly cast-wrapped) Const; false if the node is not a non-NULL Const.
static bool retype_agg_var_walker(Node *node, retype_agg_var_ctx *ctx)
Walker that retypes agg_token Vars to text and rewrites the equality OpExpr to text = text with the n...
static void rewrite_agg_cases(const constants_t *constants, Query *q)
static bool is_projected_rv_event(Node *node, const constants_t *constants)
Is node a projected random_variable comparison event?
static Query * build_outer_for_distinct_key(TargetEntry *orig_agg_te, Query *inner, int n_gb, const constants_t *constants)
Wrap inner in an outer query that applies the original aggregate.
static int provsql_executor_depth
Executor nesting depth.
static bool cond_predicate_target(const constants_t *constants, Oid opfuncid, Oid *cond_fn, Oid *result_type, bool *is_prefix)
Carrier-routing for an "X | (predicate)" placeholder OpExpr.
static Query * oj_having_gated_subquery(Query *body, Node *pred)
Build the one-row "SELECT 1 FROM <body FROM> HAVING <pred>" gated subquery: body supplies the FROM (a...
static ProcessUtility_hook_type prev_ProcessUtility
static Expr * make_provenance_expression(const constants_t *constants, Query *q, List *prov_atts, bool aggregation, bool group_by_rewrite, semiring_operation op, int **columns, int nbcols, bool wrap_assumed, bool in_boolean_rewrite, const char *inv_cert)
Build the combined provenance expression to be added to the SELECT list.
static void build_column_map(Query *q, int **columns, int *nbcols)
Build the per-RTE column-numbering map used by where-provenance.
static List * strip_given_markers(const constants_t *constants, Query *q)
Strip given(evidence) whole-tuple conditioning markers from the visible projection,...
static Node * insert_agg_token_casts_mutator(Node *node, void *data)
Insert agg_token casts for Vars used in expressions.
bool provsql_hybrid_evaluation
Run the hybrid-evaluator simplifier inside probability_evaluate; controlled by the provsql....
static bool is_null_constant_operand(Node *node)
True when node is a NULL constant (through a coercion).
static bool provsql_update_provenance
true when provenance tracking for DML is enabled
static int provsql_provenance_class
Backing variable of the provsql.provenance GUC.
static bool check_expr_on_aggregate(Expr *expr, const constants_t *constants)
Top-level dispatcher for supported WHERE-on-aggregate patterns.
static bool provenance_function_walker(Node *node, void *data)
Tree walker that returns true if any provenance() call is found.
semiring_operation
Semiring operation used to combine provenance tokens.
@ SR_PLUS
Semiring addition (UNION, SELECT DISTINCT).
@ SR_TIMES
Semiring multiplication (JOIN, Cartesian product).
@ SR_MONUS
Semiring monus / set difference (EXCEPT).
static void group_set_difference_right_arm(const constants_t *constants, Query *q)
Group the right-hand arm of a set difference by all its columns so the per-tuple right provenances ⊕-...
static bool needs_having_lift(Node *havingQual, const constants_t *constants)
Return true if havingQual contains anything the HAVING-lift path needs to handle (an agg_token Var or...
static bool join_qual_has_agg_token(Node *node, const constants_t *constants, Index *rteid, AttrNumber *join_attno)
Return true if node contains an OpExpr that equates an agg_token Var with a non-agg_token Var.
static Node * aggregation_mutator(Node *node, void *ctx)
Tree-mutator that replaces Aggrefs with provenance-aware aggregates.
static void inline_ctes(const constants_t *constants, Query *q)
Inline CTE references in q as subqueries where the rewrite needs them, preserving CTEs whose bodies n...
int provsql_joint_max_treewidth
Maximum joint treewidth the joint-width UCQ compiler attempts before declining (caller falls back to ...
static bool rewrite_predicate_sublinks(const constants_t *constants, Query *q)
Rewrite top-level EXISTS / IN WHERE conjuncts (optionally negated) over tracked relations into correl...
static bool expr_contains_agg(Node *node, const constants_t *constants)
Whether an expression subtree references an aggregate (a bare provenance_aggregate call or an agg_tok...
static Node * oj_wrap_remap_mut(Node *node, void *cx)
static OpExpr * oj_count_const_cmp(Oid opno, Oid inputcollid, Aggref *cnt, Node *constarg)
Build the "<cnt> <op> const" OpExpr for an antijoin's HAVING, where cnt is a count aggregate (count(*...
static bool expr_contains_aggref_walker(Node *node, void *context)
expression_tree_walker predicate: returns true on the first Aggref it encounters.
static void remove_provsql_from_select(Query *q)
Remove the auto-added provsql output column from a rewritten query.
static OpExpr * oj_count_cmp(Var *found_var, Index q_idx, const char *opstr, int64 n)
Build "count(Q.key) <op> n" over the decorrelated LEFT-JOIN group.
static Expr * coerce_via_io_to_text(Expr *arg)
Coerce arg to text via its output function (any type -> text).
static Expr * build_mobius_provenance_expr(const constants_t *constants, const char *desc, Expr *fallback)
Build the ucq_mobius_provenance(descriptor, fallback) call.
static Var * make_column_var(Query *q, RangeTblEntry *r, Index relid, AttrNumber attno)
A Var for column attno of RTE relid, with the column's actual type/typmod/collation,...
static Node * build_binop(const char *op, Node *l, Node *r)
Build l <op> r, resolving the operator by name.
static Node * flatten_mut(Node *node, void *cp)
Tree mutator implementing the conjunctive inlining of SPJ subqueries.
static bool expr_contains_aggref(Node *node)
Whether an expression contains a plain Aggref.
static ExecutorEnd_hook_type prev_ExecutorEnd
static bool query_has_tracked_sublink(const constants_t *constants, Query *q)
Does any SubLink in q's own clauses have a subselect that (transitively) involves a provenance-tracke...
static bool process_inert_fetches_walker(Node *node, void *cx)
bool provsql_aggtoken_text_as_uuid
When true, agg_token::text emits the underlying provenance UUID instead of "value (*)".
static FuncExpr * having_OpExpr_to_provenance_cmp(OpExpr *opExpr, const constants_t *constants, bool negated)
Convert a comparison OpExpr on aggregate results into a provenance_cmp gate expression.
static void add_select_non_zero(const constants_t *constants, Query *q, Expr *provsql)
Add a WHERE condition filtering out zero-provenance tuples.
static void reduce_varattno_by_offset(List *targetList, Index varno, int *offset)
Adjust Var attribute numbers in targetList after columns are removed.
qual_class
Categorisation of a top-level WHERE conjunct.
@ QUAL_MIXED_RV_DET
random_variable mixed with non-RV leaves; error
@ QUAL_PURE_AGG
pure agg_token expression; route to HAVING
@ QUAL_DETERMINISTIC
no probabilistic value; stays in WHERE
@ QUAL_MIXED_AGG_DET
agg_token mixed with non-agg leaves; error
@ QUAL_MIXED_AGG_RV
agg_token and random_variable in the same expr; error
@ QUAL_PURE_RV
pure random_variable expression; lift to provenance
static Node * make_uuid_array_subscript(Node *arr_expr, int index, const constants_t *constants)
Build an AST node for arr[idx] on a uuid[] expression.
static TargetEntry * agg_nulltest_target(Query *q, NullTest *nt, const constants_t *constants, Query **sub_out)
The subquery target entry an IS [NOT] NULL is testing, if it is an aggregate of a subquery in q.
static FuncExpr * rv_OpExpr_to_provenance_cmp(OpExpr *opExpr, const constants_t *constants, bool negated)
Convert a single RV-comparison OpExpr into a provenance_cmp() FuncExpr returning UUID.
static Node * try_swap_agg_arith(OpExpr *op, const constants_t *constants)
Rebuild an arithmetic operator over an aggregate so the result stays an agg_token (provenance preserv...
static Expr * make_rv_aggregate_expression(const constants_t *constants, Aggref *agg_ref, List *prov_atts, semiring_operation op)
Inline rewrite of an RV-returning aggregate, baking each aggregate's identity element into the per-ro...
static void error_for_mixed_qual(qual_class c)
Raise the user-facing error appropriate to a mixed c.
static bool has_provenance(const constants_t *constants, Query *q)
Return true if q involves any provenance-bearing relation or contains an explicit provenance() call.
static bool case_has_rv_cmp(CaseExpr *ce, const constants_t *constants)
Does a searched CASE have at least one RV-comparison guard?
static FlatAtomOrigin * flat_origin_prepend(int slot, const FlatAtomOrigin *sub)
Prepend slot to sub's path, for an atom inlined one level up.
static Node * renumber_rte_mut(Node *node, void *cx)
Mutator: renumber every Var / RangeTblRef / JoinExpr rtindex of the compacted level through old_to_ne...
static Node * peel_agg_casts(Node *n)
Peel implicit/explicit cast FuncExprs and RelabelTypes that wrap a single argument,...
static Query * oj_build_rel_query(const constants_t *constants, Query *outer, RangeTblEntry *R, oj_cols *Rc)
Build the plain-scan subquery "SELECT R.cols FROM R".
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
#define provsql_warning(fmt,...)
Emit a ProvSQL warning message (execution continues).
#define provsql_notice(fmt,...)
Emit a ProvSQL informational notice (execution continues).
void RegisterProvSQLMMapWorker(void)
Register the ProvSQL mmap background worker with PostgreSQL.
Background worker and IPC primitives for mmap-backed circuit storage.
void provsql_shmem_request(void)
Request shared memory from PostgreSQL (PG ≥ 15).
shmem_startup_hook_type prev_shmem_startup
Saved pointer to the previous shmem_startup_hook, for chaining.
void provsql_shmem_startup(void)
Initialise the ProvSQL shared-memory segment.
Shared-memory segment and inter-process pipe management.
shmem_request_hook_type prev_shmem_request
Saved pointer to the previous shmem_request_hook (PG ≥ 15), for chaining.
Oid find_equality_operator(Oid ltypeId, Oid rtypeId)
Find the equality operator OID for two given types.
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.
#define PROVSQL_COLUMN_NAME
Canonical name of the per-row provenance column installed by add_provenance / repair_key.
Query * try_safe_query_rewrite(const constants_t *constants, Query *q)
Top-level entry point for the hierarchical-CQ rewriter.
bool inversion_free_analyze(const constants_t *constants, Query *q, char **cert_out, InvFreeMarker **markers_out, int *natoms_out)
Inversion-free analysis of the lineage query q.
Public surface of the safe-query (hierarchical-CQ) rewriter.
void strip_group_rte_pg18(Query *q)
PG 18 helper: strip the synthetic RTE_GROUP entry from q in place, resolving every grouped Var back t...
Context for cte_reference_walker.
const char * name
CTE name searched for.
Where a flattened base atom came from, for mapping markers back.
Per-query marker context for the inversion-free path, threaded through the recursive query rewrite to...
Per-atom marker spec for the inversion-free path.
Memo entry mapping a recursive-CTE name to its lowered scan subquery.
Result of provsql_classify_query.
State captured by the pre-execution pass for the post-execution one.
provsql_table_kind inherited_kind
bool fire
true when the post-pass should run
uint16 source_block_key_n
Oid ancestors[PROVSQL_TABLE_INFO_MAX_ANCESTORS]
AttrNumber source_block_key[PROVSQL_TABLE_INFO_MAX_BLOCK_KEY]
Query * inner_query
cloned for safety; freed by pfree on completion
Oid source_relid
Single source whose block_key we want to align (BID only).
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.
Context for push_agg_nulltest_walker.
const constants_t * constants
Context for the aggregation_mutator tree walker.
semiring_operation op
Semiring operation for combining tokens.
const constants_t * constants
Extension OID cache.
bool is_scalar
Aggregation has no GROUP BY (single always-present row).
List * prov_atts
List of provenance Var nodes.
Context for the aggregation_type_mutator tree walker.
const constants_t * constants
Extension OID cache.
Index varattno
Attribute number of the aggregate column.
Index varno
Range-table entry index of the aggregate var.
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_RV_DIV
OID of random_variable_div(rv, rv) -> rv: builds the avg num/denom division gate.
Oid OID_AGG_AVG_RV
provsql.avg(random_variable)
Oid OID_AGG_RV_CORR_IMPL
provsql.rv_corr_impl(ind rv, x rv, y rv)
Oid OID_AGG_RV_SUM_OR_NULL
provsql.rv_sum_or_null(random_variable): the avg-numerator sum, NULL on an empty group (so avg is NUL...
Oid OID_AGG_SUM_RV
OIDs of the RV-returning aggregates, keyed for the per-aggregate identity dispatch in make_rv_aggrega...
Oid OID_FUNCTION_CHOOSE
OID of the choose(anyelement) aggregate (keeps the first non-NULL value); used to decorrelate scalar ...
Oid OID_AGG_RV_STDDEV_SAMP_IMPL
provsql.rv_stddev_samp_impl(ind rv, x rv)
Oid OID_AGG_STDDEV_SAMP_RV
provsql.stddev_samp(rv)
Oid OID_FUNCTION_ANNOTATE
OID of provsql.annotate(uuid,text)->uuid.
Oid OID_FUNCTION_PROVENANCE
OID of the provenance FUNCTION.
Oid OID_FUNCTION_RV_LEAST
provsql.least(VARIADIC random_variable[])
Oid OID_FUNCTION_RV_CASE
OID of provsql.rv_case(uuid[])->random_variable.
Oid OID_FUNCTION_INVERSION_FREE_KEY
OID of provsql.inversion_free_key(text,text,int)->text.
Oid OID_FUNCTION_AGG_VALUE_GATE
agg_value_gate(numeric) -> uuid
Oid OID_FUNCTION_AGG_TOKEN_UUID
OID of the agg_token_uuid FUNCTION.
Oid OID_AGG_STDDEV_POP_RV
provsql.stddev_pop(rv)
Oid OID_FUNCTION_RV_AGGREGATE_SEMIMOD
OID of rv_aggregate_semimod(uuid, rv) -> rv: wraps a per-row argument as mixture(prov,...
Oid OID_FUNCTION_GATE_ZERO
OID of the provenance_zero FUNCTION.
Oid OID_TYPE_RANDOM_VARIABLE_ARRAY
OID of the random_variable[] TYPE.
Oid OID_AGG_PRODUCT_RV
provsql.product(random_variable)
Oid OID_FUNCTION_COND
OID of provsql.cond(uuid,uuid)->uuid.
Oid OID_FUNCTION_PROVENANCE_PROJECT
OID of the provenance_project FUNCTION.
Oid OID_FUNCTION_RV_AGGREGATE_INDICATOR
OID of rv_aggregate_indicator(uuid) -> rv: the avg denominator wrap mixture(prov, 1,...
Oid OID_FUNCTION_GET_CHILDREN
OID of the get_children FUNCTION.
Oid OID_FUNCTION_RV_AGGREGATE_SEMIMOD_ID
OID of the 3-arg rv_aggregate_semimod(uuid, rv, float8): identity-parameterised wrap mixture(prov,...
Oid OID_UNNEST
OID of the unnest(anyarray) FUNCTION.
Oid OID_FUNCTION_COND_PREDICATE
cond_predicate(uuid,boolean)
Oid OID_AGG_MIN_RV
provsql.min(random_variable)
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.
bool ok
true if constants were loaded
Oid OID_TYPE_INT_ARRAY
OID of the INT[] TYPE.
Oid OID_AGG_RV_PERCENTILE_IMPL
provsql.rv_percentile_impl(fraction float8, ind rv, x rv)
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_FUNCTION_NOT_EQUAL_UUID
OID of the = operator on UUIDs FUNCTION.
Oid OID_FUNCTION_AGG_CASE
OID of agg_case(uuid[]), the agg_token constructor the planner hook lowers an aggregate-carrier CASE ...
Oid OID_AGG_CORR_RV
provsql.corr(rv, rv)
Oid OID_FUNCTION_GIVEN
OID of provsql.given(uuid)->uuid.
Oid OID_FUNCTION_GATE_ONE
OID of the provenance_one FUNCTION.
Oid OID_AGG_COVAR_SAMP_RV
provsql.covar_samp(rv, rv)
Oid OID_FUNCTION_RV_AGGREGATE_INDICATOR_VALUED
OID of rv_aggregate_indicator(uuid, rv) -> rv: NULL when the row's value is NULL (SQL NULL-skip for a...
Oid OID_FUNCTION_PROBABILITY_EVALUATE
OID of the real provsql.probability_evaluate(uuid,text,text).
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_PREDICATE_COND_PREDICATE
predicate_cond_predicate(boolean,boolean) – (A)|(B), both events
Oid OID_AGG_MAX_RV
provsql.max(random_variable)
Oid OID_FUNCTION_AGG_COND
OID of provsql.agg_token_cond(agg_token,uuid): the conditioning constructor for the agg_token carrier...
Oid OID_FUNCTION_PROBABILITY_PREDICATE
OID of the probability(boolean,text,text) placeholder.
Oid OID_TYPE_RANDOM_VARIABLE
OID of the random_variable TYPE.
Oid OID_AGG_COVAR_POP_RV
SQL-standard statistic aggregates over random_variable rows and their internal indicator-carrying rew...
Oid OID_FUNCTION_PROVENANCE_CMP
OID of the provenance_cmp FUNCTION.
Oid OID_AGG_PERCENTILE_CONT_RV
provsql.percentile_cont(float8) WITHIN GROUP (ORDER BY rv)
Oid OID_FUNCTION_RV_GREATEST
provsql.greatest(VARIADIC random_variable[])
Oid OID_AGG_RV_COVAR_POP_IMPL
provsql.rv_covar_pop_impl(ind rv, x rv, y rv)
Oid OID_AGG_RV_STDDEV_POP_IMPL
provsql.rv_stddev_pop_impl(ind rv, x rv)
Oid OID_AGG_RV_COVAR_SAMP_IMPL
provsql.rv_covar_samp_impl(ind rv, x rv, y rv)
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...
Oid OID_FUNCTION_PROVENANCE_CMP_TIMES
OID of the provenance_cmp_times FUNCTION.
Context for contains_agg_walker.
const constants_t * constants
Context for flatten_mut (a multi-relation conjunctive inliner).
Collector for AGG(DISTINCT) Aggrefs inside a HAVING clause.
List * aggs
Aggref* nodes carrying aggdistinct, in traversal order.
Context for replace_having_distinct_mutator: next outer RT index.
Process the inert provenance() fetches in one query's own clauses.
const constants_t * constants
Context for the insert_agg_token_casts_mutator.
const constants_t * constants
Extension OID cache.
Query * query
Outer query (to look up subquery RTEs).
Rewrite a single SELECT query to carry provenance.
List * rtable
range table owning the joinaliasvars
int sublevels_up
current query nesting depth
bool wholerow
a whole-row Var references a dissolved join
Bitmapset * flattened
rtindexes of the RTE_JOIN entries being dissolved
Context for join_qual_has_agg_token_walker.
const constants_t * constants
Extension OID cache.
Index * rteid
Out: varno of the agg_token Var.
AttrNumber * join_attno
Out: attno of the agg_token Var.
Per-relation user-column descriptor for the outer-join lowering.
Oid * coll
column collation OID
int n
number of user (non-provsql, non-dropped) columns
int32 * typmod
column typmod
Oid * type
column type OID
AttrNumber * attno
original attribute number in the base relation
Mutator: lift a scalar subquery's body into the outer query level.
Walker context: detect a Var referencing the join RTE index.
Outer Var remap context for the LEFT-join lowering: base-relation Vars (R_idx / S_idx) are retargeted...
Context for oj_param_repl_mut.
Var-renumber context: map varno from[i] → to[i].
Context for oj_replace_sublink_mut.
Mutator: replace the specific SubLink node target (by pointer) with replacement.
Walker: count SubLink nodes (capturing the first), and capture a Var referencing varno target_varno (...
Var-remap context for the FROM-wrapping pre-step: a Var at target_level on relation varno / attribute...
Context for the provenance_mutator tree walker.
bool provsql_has_aggref
true when provsql contains an Aggref (set once by replace_provenance_function_by_expression)....
bool inside_aggref
true while descending the argument tree of an Aggref node.
const constants_t * constants
Extension OID cache.
Expr * provsql
Provenance expression to substitute for provenance() calls.
Context for the reduce_varattno_mutator tree walker.
Index varno
Range-table entry whose attribute numbers are being adjusted.
int * offset
Per-attribute cumulative shift to apply.
Context for the rtindex-renumbering mutator of normalize_inner_joins.
int sublevels_up
current query nesting depth
int old_size
range-table length before compaction
int * old_to_new
1-based rtindex map; dissolved slots map to 0
Context for retype_agg_var_walker.
Index rteid
Varno of the replaced RTE.
const constants_t * constants
Extension OID cache.
AttrNumber join_attno
Attno of the former agg_token column.
Walker context for collect_source_var_types.
int32 * typmods
Matching typmod, indexed by varattno - 1.
Oid * types
Expected column type, indexed by varattno - 1.
int natts
Length of the types / typmods arrays.
Index src_rteid
Range-table index of the source subquery.
Context for sublink_classify_walker.
const constants_t * constants
bool has_unsupported_direct
Context for sublink_over_tracked_walker.
const constants_t * constants