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"
43#include "optimizer/planner.h"
44#include "parser/parse_coerce.h"
45#include "parser/parse_node.h"
46#include "parser/parse_oper.h"
47#include "rewrite/rewriteManip.h"
48#include "parser/parse_relation.h"
49#include "utils/builtins.h"
50#include "parser/parsetree.h"
51#include "storage/lwlock.h"
52#include "storage/shmem.h"
53#include "utils/fmgroids.h"
55#include "utils/lsyscache.h"
56#include "utils/ruleutils.h"
57#include "utils/syscache.h"
58#include "catalog/namespace.h"
59#include "catalog/pg_cast.h"
60#include "commands/createas.h"
61#include "executor/spi.h"
62#include "tcop/utility.h"
63#include "tcop/tcopprot.h"
73#if PG_VERSION_NUM < 100000
74#error "ProvSQL requires PostgreSQL version 10 or later"
144 bool **removed,
bool wrap_root,
bool top_level,
145 bool in_boolean_rewrite,
170 RangeTblEntry *r, Index relid,
172 Var *v = makeNode(Var);
177#if PG_VERSION_NUM >= 130000
179 v->varattnosyn = attid;
182 v->varoattno = attid;
186 v->varcollid = InvalidOid;
190#if PG_VERSION_NUM >= 160000
191 if (r->perminfoindex != 0) {
192 RTEPermissionInfo *rpi =
193 list_nth_node(RTEPermissionInfo, q->rteperminfos, r->perminfoindex - 1);
194 rpi->selectedCols = bms_add_member(
195 rpi->selectedCols, attid - FirstLowInvalidHeapAttributeNumber);
198 r->selectedCols = bms_add_member(r->selectedCols,
199 attid - FirstLowInvalidHeapAttributeNumber);
226 if (IsA(node, Var)) {
227 Var *v = (Var *)node;
229 if (v->varno == context->
varno) {
230 v->varattno += context->
offset[v->varattno - 1];
254 foreach (lc, targetList) {
255 Node *te = lfirst(lc);
272 if (IsA(node, Var)) {
273 Var *v = (Var *)node;
274 return v->varno == context->
varno && v->varattno == context->
varattno;
300 if (IsA(node, FuncExpr)) {
301 FuncExpr *f = (FuncExpr *)node;
304 if (list_length(f->args) == 1 &&
307 HeapTuple castTuple = SearchSysCache2(CASTSOURCETARGET,
309 ObjectIdGetDatum(f->funcresulttype));
311 if (HeapTupleIsValid(castTuple)) {
312 Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(castTuple);
313 if (OidIsValid(castForm->castfunc)) {
314 f->funcid = castForm->castfunc;
316 ReleaseSysCache(castTuple);
320 ((Var *)linitial(f->args))->vartype =
327 if (IsA(node, Var)) {
328 Var *v = (Var *)node;
330 if (v->varno == context->
varno && v->varattno == context->
varattno) {
351 Query *q, Index rteid,
357 foreach (lc, targetList) {
358 TargetEntry *te = (TargetEntry *)lfirst(lc);
359 if (IsA(te->expr, FuncExpr)) {
360 FuncExpr *f = (FuncExpr *)te->expr;
363 context.
varno = rteid;
366 QTW_DONT_COPY_QUERY | QTW_IGNORE_RC_SUBQUERIES);
371 foreach (lc2, q->targetList) {
372 TargetEntry *outer_te = (TargetEntry *)lfirst(lc2);
373 if (IsA(outer_te->expr, Var)) {
374 Var *v = (Var *)outer_te->expr;
375 if (v->varno == rteid && v->varattno == attno &&
376 outer_te->ressortgroupref > 0) {
378 foreach (lc3, q->sortClause) {
379 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc3);
380 if (sgc->tleSortGroupRef == outer_te->ressortgroupref)
382 "a subquery not supported");
384 foreach (lc3, q->groupClause) {
385 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc3);
386 if (sgc->tleSortGroupRef == outer_te->ressortgroupref)
388 "a subquery not supported");
414#if PG_VERSION_NUM >= 150000
421 const char *src_name;
422 const char *dst_name;
423 const char *source_text;
425 const char *source_attname;
427 const char *edge_quals;
428 const char *edge_sql;
434 foreach (lc, lowered) {
436 if (strcmp(e->
name, name) == 0)
442#if PG_VERSION_NUM >= 150000
444typedef struct ReachabilityShape {
446 AttrNumber src_attno;
447 AttrNumber dst_attno;
450 AttrNumber source_attno;
454 List *edge_rte_colnames;
462typedef struct ReachVarnosCtx {
468static bool reach_varnos_walker(Node *node, ReachVarnosCtx *ctx) {
471 if (IsA(node, Var)) {
472 Var *v = (Var *) node;
473 if (v->varlevelsup != 0)
476 ctx->varnos = bms_add_member(ctx->varnos, v->varno);
479 return expression_tree_walker(node, reach_varnos_walker, (
void *) ctx);
483static Node *reach_strip(Node *n) {
484 while (n != NULL && IsA(n, RelabelType))
485 n = (Node *) ((RelabelType *) n)->arg;
494static void reach_collect_quals(Node *jtnode, List **quals,
bool *ok) {
495 if (jtnode == NULL || !*ok)
497 if (IsA(jtnode, FromExpr)) {
498 FromExpr *f = (FromExpr *) jtnode;
500 foreach(lc, f->fromlist)
501 reach_collect_quals((Node *) lfirst(lc), quals, ok);
503 *quals = list_concat(*quals, make_ands_implicit((Expr *) f->quals));
504 }
else if (IsA(jtnode, JoinExpr)) {
505 JoinExpr *j = (JoinExpr *) jtnode;
506 if (j->jointype != JOIN_INNER) {
510 reach_collect_quals(j->larg, quals, ok);
511 reach_collect_quals(j->rarg, quals, ok);
513 *quals = list_concat(*quals, make_ands_implicit((Expr *) j->quals));
519static TargetEntry *reach_single_tle(Query *q) {
520 TargetEntry *res = NULL;
522 foreach(lc, q->targetList) {
523 TargetEntry *te = (TargetEntry *) lfirst(lc);
534static bool reach_two_tles(Query *q, TargetEntry *out[2]) {
536 out[0] = out[1] = NULL;
537 foreach(lc, q->targetList) {
538 TargetEntry *te = (TargetEntry *) lfirst(lc);
541 if (te->resno < 1 || te->resno > 2 || out[te->resno - 1] != NULL)
543 out[te->resno - 1] = te;
545 return out[0] != NULL && out[1] != NULL;
549static bool reach_int_const(Node *n, int64 *value) {
550 Const *c = (Const *) reach_strip(n);
551 if (c == NULL || !IsA(c, Const) || c->constisnull)
553 switch (c->consttype) {
555 *value = DatumGetInt16(c->constvalue);
558 *value = DatumGetInt32(c->constvalue);
561 *value = DatumGetInt64(c->constvalue);
573static bool reach_is_hop_increment(Node *n, Index cte_rti, AttrNumber resno) {
574 OpExpr *op = (OpExpr *) reach_strip(n);
579 if (op == NULL || !IsA(op, OpExpr) || list_length(op->args) != 2)
581 opname = get_opname(op->opno);
582 is_plus = opname != NULL && strcmp(opname,
"+") == 0;
587 if (reach_int_const((Node *) lsecond(op->args), &one))
588 v = (Var *) reach_strip((Node *) linitial(op->args));
589 else if (reach_int_const((Node *) linitial(op->args), &one))
590 v = (Var *) reach_strip((Node *) lsecond(op->args));
593 if (one != 1 || v == NULL || !IsA(v, Var))
595 return v->varno == cte_rti && v->varlevelsup == 0 && v->varattno == resno;
603static bool reach_is_hop_bound(Node *n, Index cte_rti, AttrNumber hops_pos,
604 int64 *bound,
bool *strict) {
605 OpExpr *op = (OpExpr *) reach_strip(n);
609 if (op == NULL || !IsA(op, OpExpr) || list_length(op->args) != 2)
611 v = (Var *) reach_strip((Node *) linitial(op->args));
612 if (v != NULL && IsA(v, Var) &&
613 reach_int_const((Node *) lsecond(op->args), bound))
616 v = (Var *) reach_strip((Node *) lsecond(op->args));
617 if (v == NULL || !IsA(v, Var) ||
618 !reach_int_const((Node *) linitial(op->args), bound))
622 if (v->varno != cte_rti || v->varlevelsup != 0 || v->varattno != hops_pos)
624 opname = get_opname(op->opno);
628 if (strcmp(opname, var_first ?
"<" :
">") == 0)
630 else if (strcmp(opname, var_first ?
"<=" :
">=") == 0)
678static bool detect_reachability_cte(CommonTableExpr *cte, Query *cteq,
680 ReachabilityShape *out) {
681 SetOperationStmt *so = (SetOperationStmt *) cteq->setOperations;
683 Query *base = NULL, *rec = NULL;
684 Index edge_rti = 0, cte_rti = 0;
691 Var *va, *vb, *edge_var, *cte_var;
692 AttrNumber prov_attno;
696 AttrNumber node_pos = 1, hops_pos = 0;
697 TargetEntry *base_tles[2], *rec_tles[2];
700 if (list_length(cte->ctecolnames) == 1)
702 else if (list_length(cte->ctecolnames) == 2)
707 if (!IsA(so->larg, RangeTblRef) || !IsA(so->rarg, RangeTblRef))
709 for (i = 0; i < 2; ++i) {
710 RangeTblRef *rtr = (RangeTblRef *) (i == 0 ? so->larg : so->rarg);
711 RangeTblEntry *r = rt_fetch(rtr->rtindex, cteq->rtable);
712 if (r->rtekind != RTE_SUBQUERY || r->subquery == NULL)
714 arms[i] = r->subquery;
720 Index rec_self_rti = 0;
721 for (i = 0; i < 2; ++i) {
722 bool has_self =
false;
723 Index rti = 0, self_rti = 0;
724 foreach(lc, arms[i]->rtable) {
725 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
727 if (r->rtekind == RTE_CTE && r->self_reference &&
728 strcmp(r->ctename, cte->ctename) == 0) {
737 rec_self_rti = self_rti;
744 if (base == NULL || rec == NULL)
753 if (!reach_two_tles(rec, rec_tles) || !reach_two_tles(base, base_tles))
755 for (i = 0; i < 2; ++i)
756 if (reach_is_hop_increment((Node *) rec_tles[i]->expr, rec_self_rti,
757 (AttrNumber) (i + 1))) {
758 hops_pos = (AttrNumber) (i + 1);
763 node_pos = (AttrNumber) (3 - hops_pos);
764 if (!reach_int_const((Node *) base_tles[hops_pos - 1]->expr, &hop_seed))
766 if (hop_seed < PG_INT32_MIN/2 || hop_seed > PG_INT32_MAX/2)
774 if (base->setOperations != NULL || base->hasAggs || base->hasSubLinks ||
775 base->hasTargetSRFs || base->groupClause != NIL ||
776 base->distinctClause != NIL || base->jointree == NULL ||
777 base->jointree->quals != NULL)
779 tle = hops_mode ? base_tles[node_pos - 1] : reach_single_tle(base);
782 if (base->jointree->fromlist == NIL) {
783 Node *bexpr = reach_strip((Node *) tle->expr);
787 if (bexpr == NULL || !IsA(bexpr, Const))
792 getTypeOutputInfo(c->consttype, &outfunc, &varlena);
793 out->source_text = OidOutputFunctionCall(outfunc, c->constvalue);
795 RangeTblEntry *srel = NULL;
799 if (list_length(base->jointree->fromlist) != 1 ||
800 !IsA(linitial(base->jointree->fromlist), RangeTblRef))
802 foreach(lc, base->rtable) {
803 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
805 if (r->rtekind != RTE_RELATION || r->relkind != RELKIND_RELATION)
814 sv = (Var *) reach_strip((Node *) tle->expr);
815 if (sv == NULL || !IsA(sv, Var) || sv->varno != srel_rti ||
816 sv->varlevelsup != 0 || sv->varattno <= 0)
821 if (sprov != InvalidAttrNumber && sv->varattno == sprov)
824 out->source_relid = srel->relid;
825 out->source_attno = sv->varattno;
829 if (rec->hasAggs || rec->hasWindowFuncs || rec->hasSubLinks ||
830 rec->hasTargetSRFs || rec->groupClause != NIL ||
831 rec->distinctClause != NIL || rec->sortClause != NIL ||
832 rec->havingQual != NULL || rec->limitOffset != NULL ||
833 rec->limitCount != NULL || rec->setOperations != NULL ||
834 rec->groupingSets != NIL)
838 RangeTblEntry *edge_rte = NULL;
839 foreach(lc, rec->rtable) {
840 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
842 switch (r->rtekind) {
844 if (edge_rti != 0 || r->relkind != RELKIND_RELATION)
848 out->relid = r->relid;
856 if (edge_rti != 0 || r->subquery == NULL)
860 out->relid = InvalidOid;
861 out->edge_sql = pg_get_querydef(copyObject(r->subquery),
false);
864 if (cte_rti != 0 || !r->self_reference ||
865 strcmp(r->ctename, cte->ctename) != 0)
875 if (edge_rti == 0 || cte_rti == 0)
878 if (OidIsValid(out->relid)) {
882 if (prov_attno == InvalidAttrNumber ||
883 get_atttype(out->relid, prov_attno) != constants->OID_TYPE_UUID)
886 prov_attno = InvalidAttrNumber;
888 out->edge_rte_colnames = edge_rte->eref->colnames;
896 reach_collect_quals((Node *) rec->jointree, &quals, &ok);
900 List *edge_only = NIL;
901 bool have_bound =
false;
906 Node *q = (Node *) lfirst(lc);
907 ReachVarnosCtx vctx = {NULL,
false};
908 reach_varnos_walker(q, &vctx);
911 if (bms_is_member(cte_rti, vctx.varnos)) {
914 if (hops_mode && !have_bound &&
915 reach_is_hop_bound(q, cte_rti, hops_pos, &bound, &strict))
917 else if (join_qual == NULL)
921 }
else if (bms_is_subset(vctx.varnos, bms_make_singleton(edge_rti))) {
924 if (contain_volatile_functions(q))
926 edge_only = lappend(edge_only, q);
930 if (join_qual == NULL)
939 max_len = bound - hop_seed + (strict ? 0 : 1);
944 out->hop_bound = (int) max_len;
945 out->hop_seed = (int) hop_seed;
946 out->hops_position = hops_pos;
948 out->node_position = node_pos;
949 if (edge_only != NIL && !OidIsValid(out->relid))
951 if (edge_only != NIL) {
954 Node *conj = (Node *) make_ands_explicit(edge_only);
956 conj = copyObject(conj);
957 ChangeVarNodes(conj, edge_rti, 1, 0);
958 dpcontext = deparse_context_for(get_rel_name(out->relid), out->relid);
959 out->edge_quals = deparse_expression(conj, dpcontext,
false,
false);
964 tle = hops_mode ? rec_tles[node_pos - 1] : reach_single_tle(rec);
968 Node *texpr = reach_strip((Node *) tle->expr);
969 if (texpr != NULL && IsA(texpr, Var)) {
970 target_var = (Var *) texpr;
971 if (target_var->varno != edge_rti || target_var->varlevelsup != 0 ||
972 target_var->varattno <= 0 || target_var->varattno == prov_attno)
974 out->dst_attno = target_var->varattno;
976 if (!IsA(join_qual, OpExpr))
978 eq = (OpExpr *) join_qual;
979 if (list_length(eq->args) != 2)
981 va = (Var *) reach_strip((Node *) linitial(eq->args));
982 vb = (Var *) reach_strip((Node *) lsecond(eq->args));
983 if (va == NULL || vb == NULL || !IsA(va, Var) || !IsA(vb, Var) ||
984 va->varlevelsup != 0 || vb->varlevelsup != 0)
986 if (!op_mergejoinable(eq->opno, exprType((Node *) linitial(eq->args))))
988 if (va->varno == edge_rti && vb->varno == cte_rti)
989 edge_var = va, cte_var = vb;
990 else if (vb->varno == edge_rti && va->varno == cte_rti)
991 edge_var = vb, cte_var = va;
994 if (cte_var->varattno != node_pos || edge_var->varattno <= 0 ||
995 edge_var->varattno == prov_attno)
997 out->src_attno = edge_var->varattno;
998 out->directed =
true;
1007 if (texpr != NULL && IsA(texpr, CaseExpr)) {
1008 CaseExpr *ce = (CaseExpr *) texpr;
1011 Var *wa, *wb, *wedge, *wcte, *res, *def;
1012 AttrNumber col_a, col_b;
1014 if (ce->arg != NULL || list_length(ce->args) != 1 ||
1015 ce->defresult == NULL)
1017 cw = (CaseWhen *) linitial(ce->args);
1018 if (!IsA(cw->expr, OpExpr))
1020 weq = (OpExpr *) cw->expr;
1021 if (list_length(weq->args) != 2 ||
1022 !op_mergejoinable(weq->opno, exprType((Node *) linitial(weq->args))))
1024 wa = (Var *) reach_strip((Node *) linitial(weq->args));
1025 wb = (Var *) reach_strip((Node *) lsecond(weq->args));
1026 if (wa == NULL || wb == NULL || !IsA(wa, Var) || !IsA(wb, Var) ||
1027 wa->varlevelsup != 0 || wb->varlevelsup != 0)
1029 if (wa->varno == edge_rti && wb->varno == cte_rti)
1030 wedge = wa, wcte = wb;
1031 else if (wb->varno == edge_rti && wa->varno == cte_rti)
1032 wedge = wb, wcte = wa;
1035 if (wcte->varattno != node_pos)
1037 res = (Var *) reach_strip((Node *) cw->result);
1038 def = (Var *) reach_strip((Node *) ce->defresult);
1039 if (res == NULL || def == NULL || !IsA(res, Var) || !IsA(def, Var) ||
1040 res->varno != edge_rti || def->varno != edge_rti ||
1041 res->varlevelsup != 0 || def->varlevelsup != 0)
1045 col_a = wedge->varattno;
1046 col_b = res->varattno;
1047 if (def->varattno != col_a || col_a == col_b ||
1048 col_a <= 0 || col_b <= 0 ||
1049 col_a == prov_attno || col_b == prov_attno)
1054 AttrNumber got[2] = {0, 0};
1056 if (IsA(join_qual, BoolExpr) &&
1057 ((BoolExpr *) join_qual)->boolop == OR_EXPR &&
1058 list_length(((BoolExpr *) join_qual)->args) == 2) {
1060 foreach(olc, ((BoolExpr *) join_qual)->args) {
1061 OpExpr *oeq = (OpExpr *) lfirst(olc);
1062 Var *oa, *ob, *oedge, *octe;
1063 if (!IsA(oeq, OpExpr) || list_length(oeq->args) != 2 ||
1064 !op_mergejoinable(oeq->opno,
1065 exprType((Node *) linitial(oeq->args))))
1067 oa = (Var *) reach_strip((Node *) linitial(oeq->args));
1068 ob = (Var *) reach_strip((Node *) lsecond(oeq->args));
1069 if (oa == NULL || ob == NULL || !IsA(oa, Var) || !IsA(ob, Var))
1071 if (oa->varno == edge_rti && ob->varno == cte_rti)
1072 oedge = oa, octe = ob;
1073 else if (ob->varno == edge_rti && oa->varno == cte_rti)
1074 oedge = ob, octe = oa;
1077 if (octe->varattno != node_pos || n >= 2)
1079 got[n++] = oedge->varattno;
1081 }
else if (IsA(join_qual, ScalarArrayOpExpr)) {
1082 ScalarArrayOpExpr *sao = (ScalarArrayOpExpr *) join_qual;
1086 if (!sao->useOr || list_length(sao->args) != 2 ||
1087 !op_mergejoinable(sao->opno,
1088 exprType((Node *) linitial(sao->args))))
1090 scte = (Var *) reach_strip((Node *) linitial(sao->args));
1091 if (scte == NULL || !IsA(scte, Var) || scte->varno != cte_rti ||
1092 scte->varattno != node_pos)
1094 arr = (ArrayExpr *) reach_strip((Node *) lsecond(sao->args));
1095 if (arr == NULL || !IsA(arr, ArrayExpr) ||
1096 list_length(arr->elements) != 2)
1098 foreach(alc, arr->elements) {
1099 Var *ev = (Var *) reach_strip((Node *) lfirst(alc));
1100 if (ev == NULL || !IsA(ev, Var) || ev->varno != edge_rti ||
1103 got[n++] = ev->varattno;
1108 !((got[0] == col_a && got[1] == col_b) ||
1109 (got[0] == col_b && got[1] == col_a)))
1113 out->src_attno = col_a;
1114 out->dst_attno = col_b;
1115 out->directed =
false;
1123#if PG_VERSION_NUM >= 150000
1144static bool lower_recursive_cte(CommonTableExpr *cte, RangeTblEntry *r,
1146 Query *cteq = (Query *) cte->ctequery;
1148 StringInfoData cols, coldef, call, scan;
1149 ListCell *lcn, *lct;
1153 if (cteq == NULL || !IsA(cteq, Query))
1160 if (cteq->setOperations == NULL ||
1161 !IsA(cteq->setOperations, SetOperationStmt) ||
1162 ((SetOperationStmt *) cteq->setOperations)->op != SETOP_UNION ||
1163 ((SetOperationStmt *) cteq->setOperations)->all)
1175 foreach(lc, cteq->rtable) {
1176 RangeTblEntry *sub = (RangeTblEntry *) lfirst(lc);
1177 if (sub->rtekind == RTE_SUBQUERY && sub->subquery != NULL &&
1178 sub->subquery->hasTargetSRFs)
1185 body_text = pg_get_querydef(cteq,
false);
1188 initStringInfo(&cols);
1189 initStringInfo(&coldef);
1190 forboth(lcn, cte->ctecolnames, lct, cte->ctecoltypes) {
1191 char *name = strVal(lfirst(lcn));
1192 Oid typid = lfirst_oid(lct);
1194 appendStringInfoString(&cols,
", ");
1195 appendStringInfoString(&coldef,
", ");
1198 appendStringInfoString(&cols, quote_identifier(name));
1199 appendStringInfo(&coldef,
"%s %s", quote_identifier(name), format_type_be(typid));
1203 provsql_notice(
"Lowering recursive CTE '%s':\n body = %s\n coldef = %s",
1204 cte->ctename, body_text, coldef.data);
1219 initStringInfo(&call);
1221 ReachabilityShape shape = {InvalidOid, 0, 0, NULL, InvalidOid, 0,
true,
1222 NULL, NULL, NIL, -1, 0, 0, 1};
1225 detect_reachability_cte(cte, cteq, &constants, &shape)) {
1228 char *coltype = format_type_be(
1229 list_nth_oid(cte->ctecoltypes, shape.node_position - 1));
1230 StringInfoData relarg;
1231 if (OidIsValid(shape.relid)) {
1232 src_name = get_attname(shape.relid, shape.src_attno,
false);
1233 dst_name = get_attname(shape.relid, shape.dst_attno,
false);
1235 src_name = strVal(list_nth(shape.edge_rte_colnames,
1236 shape.src_attno - 1));
1237 dst_name = strVal(list_nth(shape.edge_rte_colnames,
1238 shape.dst_attno - 1));
1240 initStringInfo(&relarg);
1241 if (OidIsValid(shape.relid))
1242 appendStringInfo(&relarg,
"%u::pg_catalog.regclass", shape.relid);
1244 appendStringInfoString(&relarg,
"NULL::pg_catalog.regclass");
1246 provsql_notice(
"Recursive CTE '%s' recognised as reachability over %s",
1248 OidIsValid(shape.relid) ? get_rel_name(shape.relid)
1249 :
"a join-defined edge query");
1253 if (entry != NULL && shape.hop_bound < 0) {
1254 entry->reach_routed =
true;
1255 entry->edge_relid = shape.relid;
1256 entry->src_name = pstrdup(src_name);
1257 entry->dst_name = pstrdup(dst_name);
1258 entry->source_text =
1259 shape.source_text ? pstrdup(shape.source_text) : NULL;
1260 entry->source_relid = shape.source_relid;
1261 entry->source_attname =
1262 OidIsValid(shape.source_relid)
1263 ? get_attname(shape.source_relid, shape.source_attno,
false)
1265 entry->directed = shape.directed;
1267 shape.edge_quals ? pstrdup(shape.edge_quals) : NULL;
1268 entry->edge_sql = shape.edge_sql ? pstrdup(shape.edge_sql) : NULL;
1270 appendStringInfo(&call,
1271 "SELECT provsql.eval_reachability(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
1273 quote_literal_cstr(src_name),
1274 quote_literal_cstr(dst_name),
1276 ? quote_literal_cstr(shape.source_text) :
"NULL",
1277 shape.directed ?
"true" :
"false",
1278 quote_literal_cstr(cte->ctename),
1279 quote_literal_cstr(cols.data),
1280 quote_literal_cstr(coldef.data),
1281 quote_literal_cstr(coltype),
1282 quote_literal_cstr(body_text),
1284 ? quote_literal_cstr(shape.edge_quals) :
"NULL");
1285 if (OidIsValid(shape.source_relid)) {
1286 char *satt = get_attname(shape.source_relid, shape.source_attno,
1288 appendStringInfo(&call,
", %u::pg_catalog.regclass, %s",
1289 shape.source_relid, quote_literal_cstr(satt));
1290 }
else if (shape.edge_sql != NULL)
1291 appendStringInfoString(&call,
", NULL, NULL");
1292 if (shape.edge_sql != NULL)
1293 appendStringInfo(&call,
", %s", quote_literal_cstr(shape.edge_sql));
1294 if (shape.hop_bound >= 0)
1295 appendStringInfo(&call,
1296 ", hop_bound => %d, hop_seed => %d, hops_position => %d",
1297 shape.hop_bound, shape.hop_seed,
1298 shape.hops_position);
1299 appendStringInfoString(&call,
")");
1301 appendStringInfo(&call,
"SELECT provsql.eval_recursive(%s, %s, %s, %s)",
1302 quote_literal_cstr(body_text),
1303 quote_literal_cstr(cte->ctename),
1304 quote_literal_cstr(cols.data),
1305 quote_literal_cstr(coldef.data));
1308 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
1309 provsql_error(
"Recursive CTE lowering: SPI_connect failed (%d)", rc);
1310 rc = SPI_execute(call.data,
false, 0);
1313 provsql_error(
"Recursive CTE lowering: eval_recursive failed (%d)", rc);
1316 initStringInfo(&scan);
1317 appendStringInfo(&scan,
"SELECT %s FROM %s",
1318 cols.data, quote_identifier(cte->ctename));
1320 List *raw = pg_parse_query(scan.data);
1321 List *analyzed = pg_analyze_and_rewrite_fixedparams(
1322 linitial_node(RawStmt, raw), scan.data, NULL, 0, NULL);
1323 r->rtekind = RTE_SUBQUERY;
1324 r->subquery = linitial_node(Query, analyzed);
1349 foreach (lc, rtable) {
1350 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
1351 if (r->rtekind == RTE_CTE) {
1353 foreach (lc2, cteList) {
1354 CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc2);
1355 if (strcmp(cte->ctename, r->ctename) == 0) {
1356 if (cte->cterecursive) {
1357#if PG_VERSION_NUM >= 150000
1365 r->rtekind = RTE_SUBQUERY;
1366 r->subquery = copyObject(memo);
1371 if (lower_recursive_cte(cte, r, e)) {
1374 e->
name = pstrdup(cte->ctename);
1375 e->
subquery = copyObject(r->subquery);
1376 *lowered = lappend(*lowered, e);
1379 provsql_error(
"Recursive CTEs not supported (unsupported recursion shape)");
1385 r->rtekind = RTE_SUBQUERY;
1386 r->subquery = copyObject((Query *)cte->ctequery);
1396 }
else if (r->rtekind == RTE_SUBQUERY && r->subquery != NULL) {
1404#if PG_VERSION_NUM >= 150000
1409} ReachMemberQualCtx;
1417static bool reach_member_local_walker(Node *node, ReachMemberQualCtx *ctx) {
1420 if (IsA(node, Var)) {
1421 Var *v = (Var *) node;
1422 if (v->varlevelsup != 0 || v->varno != ctx->t_rti)
1426 if (IsA(node, SubLink) || IsA(node, Param)) {
1430 return expression_tree_walker(node, reach_member_local_walker, ctx);
1438static bool reach_member_local_qual(Node *qual, Index t_rti) {
1439 ReachMemberQualCtx ctx = { t_rti,
true };
1440 reach_member_local_walker(qual, &ctx);
1445typedef struct ReachAggCandidate {
1446 const char *ctename;
1447 const char *node_colname;
1449 const char *member_attname;
1450 const char *group_attname;
1451 const char *member_quals;
1476static List *detect_reach_aggregations(Query *q) {
1479 Index rti = 0, cte_rti = 0, t_rti = 0;
1480 RangeTblEntry *cte_rte = NULL, *t_rte = NULL;
1481 SortGroupClause *sgc;
1482 TargetEntry *gtle = NULL;
1485 List *member_quals = NIL;
1488 Var *cte_var, *t_var;
1489 CommonTableExpr *cte = NULL;
1490 ReachAggCandidate *cand;
1492 if (q->setOperations != NULL || list_length(q->groupClause) != 1 ||
1493 q->groupingSets != NIL || q->cteList == NIL)
1496 foreach(lc, q->rtable) {
1497 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1499 switch (r->rtekind) {
1501 if (cte_rti != 0 || r->ctelevelsup != 0)
1507 if (t_rti != 0 || r->relkind != RELKIND_RELATION)
1513#if PG_VERSION_NUM >= 180000
1522 if (cte_rti == 0 || t_rti == 0)
1528 foreach(lc, q->cteList) {
1529 CommonTableExpr *c = (CommonTableExpr *) lfirst(lc);
1530 if (strcmp(c->ctename, cte_rte->ctename) == 0) {
1535 if (cte == NULL || !cte->cterecursive ||
1536 list_length(cte->ctecolnames) != 1)
1540 sgc = (SortGroupClause *) linitial(q->groupClause);
1541 foreach(lc, q->targetList) {
1542 TargetEntry *te = (TargetEntry *) lfirst(lc);
1543 if (te->ressortgroupref == sgc->tleSortGroupRef) {
1550 gvar = (Var *) reach_strip((Node *) gtle->expr);
1551#if PG_VERSION_NUM >= 180000
1554 if (q->hasGroupRTE && gvar != NULL && IsA(gvar, Var) &&
1555 gvar->varlevelsup == 0) {
1557 foreach(lc, q->rtable) {
1558 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1559 if (r->rtekind == RTE_GROUP) {
1560 if (gvar->varno == gidx && gvar->varattno >= 1 &&
1561 gvar->varattno <= list_length(r->groupexprs))
1562 gvar = (Var *) reach_strip(
1563 (Node *) list_nth(r->groupexprs, gvar->varattno - 1));
1570 if (gvar == NULL || !IsA(gvar, Var) || gvar->varno != t_rti ||
1571 gvar->varlevelsup != 0 || gvar->varattno <= 0)
1580 cte_var = t_var = NULL;
1581 reach_collect_quals((Node *) q->jointree, &quals, &ok);
1582 if (!ok || quals == NIL)
1584 foreach(lc, quals) {
1585 Node *qual = (Node *) lfirst(lc);
1588 if (cte_var == NULL && IsA(qual, OpExpr)) {
1589 eq = (OpExpr *) qual;
1590 if (list_length(eq->args) == 2 &&
1591 op_mergejoinable(eq->opno, exprType((Node *) linitial(eq->args)))) {
1592 Var *ja = (Var *) reach_strip((Node *) linitial(eq->args));
1593 Var *jb = (Var *) reach_strip((Node *) lsecond(eq->args));
1594 if (ja != NULL && jb != NULL && IsA(ja, Var) && IsA(jb, Var) &&
1595 ja->varlevelsup == 0 && jb->varlevelsup == 0) {
1596 if (ja->varno == cte_rti && jb->varno == t_rti) {
1600 }
else if (jb->varno == cte_rti && ja->varno == t_rti) {
1610 if (!reach_member_local_qual(qual, t_rti) ||
1611 contain_volatile_functions(qual))
1613 member_quals = lappend(member_quals, qual);
1615 if (cte_var == NULL)
1617 if (cte_var->varattno != 1 || t_var->varattno <= 0)
1620 cand = (ReachAggCandidate *) palloc(
sizeof(ReachAggCandidate));
1621 cand->ctename = pstrdup(cte->ctename);
1622 cand->node_colname = pstrdup(strVal(linitial(cte->ctecolnames)));
1623 cand->member_relid = t_rte->relid;
1624 cand->member_attname = get_attname(t_rte->relid, t_var->varattno,
false);
1625 cand->group_attname = get_attname(t_rte->relid, gvar->varattno,
false);
1626 cand->member_quals = NULL;
1627 if (member_quals != NIL) {
1633 Node *conj = (Node *) make_ands_explicit(member_quals);
1635 conj = copyObject(conj);
1636 ChangeVarNodes(conj, t_rti, 1, 0);
1637 dpcontext = deparse_context_for(
"t", t_rte->relid);
1638 cand->member_quals = deparse_expression(conj, dpcontext,
true,
false);
1640 out = lappend(out, cand);
1651static void plant_reach_aggregations(List *candidates, List *lowered) {
1653 foreach(lc, candidates) {
1654 ReachAggCandidate *cand = (ReachAggCandidate *) lfirst(lc);
1657 StringInfoData call;
1659 foreach(ll, lowered) {
1661 if (strcmp(e->
name, cand->ctename) == 0) {
1666 if (entry == NULL || !entry->reach_routed)
1669 initStringInfo(&call);
1670 appendStringInfo(&call,
1671 "SELECT provsql.plant_reach_any_groups(%s, %s, %u::pg_catalog.regclass, %s, %s, ",
1672 quote_literal_cstr(cand->ctename),
1673 quote_literal_cstr(cand->node_colname),
1675 quote_literal_cstr(cand->member_attname),
1676 quote_literal_cstr(cand->group_attname));
1677 if (OidIsValid(entry->edge_relid))
1678 appendStringInfo(&call,
"%u::pg_catalog.regclass", entry->edge_relid);
1680 appendStringInfoString(&call,
"NULL::pg_catalog.regclass");
1681 appendStringInfo(&call,
", %s, %s, %s, %s, %s, ",
1682 quote_literal_cstr(entry->src_name),
1683 quote_literal_cstr(entry->dst_name),
1685 ? quote_literal_cstr(entry->source_text) :
"NULL",
1686 entry->directed ?
"true" :
"false",
1688 ? quote_literal_cstr(entry->edge_quals) :
"NULL");
1689 if (OidIsValid(entry->source_relid))
1690 appendStringInfo(&call,
"%u::pg_catalog.regclass, %s, ",
1691 entry->source_relid,
1692 quote_literal_cstr(entry->source_attname));
1694 appendStringInfoString(&call,
"NULL, NULL, ");
1695 appendStringInfo(&call,
"%s, %s)",
1697 ? quote_literal_cstr(entry->edge_sql) :
"NULL",
1699 ? quote_literal_cstr(cand->member_quals) :
"NULL");
1701 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
1702 provsql_error(
"Reachability aggregation planting: SPI_connect failed (%d)", rc);
1703 rc = SPI_execute(call.data,
false, 0);
1706 provsql_error(
"Reachability aggregation planting failed (%d)", rc);
1711typedef struct ReachConjCandidate {
1712 const char *ctename;
1713 const char *node_colname;
1716} ReachConjCandidate;
1743static List *detect_reach_conjunctions(Query *q) {
1747 RangeTblEntry *cte_rte = NULL;
1748 CommonTableExpr *cte = NULL;
1752 List *const_texts = NIL;
1753 ReachConjCandidate *cand;
1755 if (q->setOperations != NULL || q->groupClause != NIL ||
1756 q->groupingSets != NIL || q->distinctClause != NIL ||
1757 q->havingQual != NULL || q->hasAggs || q->hasWindowFuncs ||
1758 q->hasSubLinks || q->cteList == NIL)
1761 foreach(lc, q->rtable) {
1762 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1764 switch (r->rtekind) {
1766 if (r->ctelevelsup != 0)
1768 if (cte_rte == NULL)
1770 else if (strcmp(cte_rte->ctename, r->ctename) != 0)
1785 foreach(lc, q->cteList) {
1786 CommonTableExpr *c = (CommonTableExpr *) lfirst(lc);
1787 if (strcmp(c->ctename, cte_rte->ctename) == 0) {
1792 if (cte == NULL || !cte->cterecursive ||
1793 list_length(cte->ctecolnames) != 1)
1798 reach_collect_quals((Node *) q->jointree, &quals, &ok);
1799 if (!ok || list_length(quals) != nb_refs)
1801 bound = (Node **) palloc0(
sizeof(Node *) * (list_length(q->rtable) + 1));
1802 foreach(lc, quals) {
1807 if (!IsA(lfirst(lc), OpExpr))
1809 eq = (OpExpr *) lfirst(lc);
1810 if (list_length(eq->args) != 2 ||
1811 !op_mergejoinable(eq->opno, exprType((Node *) linitial(eq->args))))
1813 na = reach_strip((Node *) linitial(eq->args));
1814 nb = reach_strip((Node *) lsecond(eq->args));
1815 if (na != NULL && IsA(na, Var) && nb != NULL && IsA(nb, Const)) {
1818 }
else if (nb != NULL && IsA(nb, Var) && na != NULL && IsA(na, Const)) {
1823 if (v->varlevelsup != 0 || v->varattno != 1 ||
1824 v->varno < 1 || v->varno > (Index) list_length(q->rtable) ||
1825 list_nth_node(RangeTblEntry, q->rtable, v->varno - 1)->rtekind
1828 if (c->constisnull || bound[v->varno] != NULL)
1830 bound[v->varno] = (Node *) c;
1836 foreach(lc, q->rtable) {
1837 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
1839 if (r->rtekind != RTE_CTE)
1841 if (bound[rti] == NULL)
1844 Const *c = (Const *) bound[rti];
1847 getTypeOutputInfo(c->consttype, &out_func, &is_varlena);
1848 const_texts = lappend(const_texts,
1849 OidOutputFunctionCall(out_func, c->constvalue));
1853 cand = (ReachConjCandidate *) palloc(
sizeof(ReachConjCandidate));
1854 cand->ctename = pstrdup(cte->ctename);
1855 cand->node_colname = pstrdup(strVal(linitial(cte->ctecolnames)));
1856 cand->const_texts = const_texts;
1857 return list_make1(cand);
1867static void plant_reach_conjunctions(List *candidates, List *lowered) {
1869 foreach(lc, candidates) {
1870 ReachConjCandidate *cand = (ReachConjCandidate *) lfirst(lc);
1873 StringInfoData call;
1876 foreach(ll, lowered) {
1878 if (strcmp(e->
name, cand->ctename) == 0) {
1883 if (entry == NULL || !entry->reach_routed)
1886 initStringInfo(&call);
1887 appendStringInfo(&call,
1888 "SELECT provsql.plant_reach_cover(%s, %s, ",
1889 quote_literal_cstr(cand->ctename),
1890 quote_literal_cstr(cand->node_colname));
1891 if (OidIsValid(entry->edge_relid))
1892 appendStringInfo(&call,
"%u::pg_catalog.regclass", entry->edge_relid);
1894 appendStringInfoString(&call,
"NULL::pg_catalog.regclass");
1895 appendStringInfo(&call,
", %s, %s, %s, %s, ",
1896 quote_literal_cstr(entry->src_name),
1897 quote_literal_cstr(entry->dst_name),
1899 ? quote_literal_cstr(entry->source_text) :
"NULL",
1900 entry->directed ?
"true" :
"false");
1901 appendStringInfoString(&call,
"ARRAY[");
1902 foreach(ll, cand->const_texts) {
1903 appendStringInfo(&call,
"%s%s", first ?
"" :
", ",
1904 quote_literal_cstr((
const char *) lfirst(ll)));
1907 appendStringInfo(&call,
"]::text[], %s, ",
1909 ? quote_literal_cstr(entry->edge_quals) :
"NULL");
1910 if (OidIsValid(entry->source_relid))
1911 appendStringInfo(&call,
"%u::pg_catalog.regclass, %s, ",
1912 entry->source_relid,
1913 quote_literal_cstr(entry->source_attname));
1915 appendStringInfoString(&call,
"NULL, NULL, ");
1916 appendStringInfo(&call,
"%s)",
1918 ? quote_literal_cstr(entry->edge_sql) :
"NULL");
1920 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
1921 provsql_error(
"Reachability conjunction planting: SPI_connect failed (%d)", rc);
1922 rc = SPI_execute(call.data,
false, 0);
1925 provsql_error(
"Reachability conjunction planting failed (%d)", rc);
1934 List *lowered = NIL;
1935#if PG_VERSION_NUM >= 150000
1936 List *reach_aggs = NIL;
1937 List *reach_conjs = NIL;
1939 if (q->cteList == NIL)
1941#if PG_VERSION_NUM >= 150000
1946 reach_aggs = detect_reach_aggregations(q);
1947 reach_conjs = detect_reach_conjunctions(q);
1950#if PG_VERSION_NUM >= 150000
1951 plant_reach_aggregations(reach_aggs, lowered);
1952 plant_reach_conjunctions(reach_conjs, lowered);
1986 bool in_boolean_rewrite,
1988 List *prov_atts = NIL;
1990 for(Index rteid = 1; rteid <= q->rtable->length; ++rteid) {
1991 RangeTblEntry *r = list_nth_node(RangeTblEntry, q->rtable, rteid-1);
1993 if (r->rtekind == RTE_RELATION) {
1995 AttrNumber attid = 1;
2004 if (r->relkind == RELKIND_VIEW)
2007 foreach (lc, r->eref->colnames) {
2008 const char *v = strVal(lfirst(lc));
2019 }
else if (r->rtekind == RTE_SUBQUERY) {
2020 bool *inner_removed = NULL;
2021 int old_targetlist_length =
2022 r->subquery->targetList ? r->subquery->targetList->length : 0;
2023 Query *new_subquery =
2024 process_query(constants, r->subquery, &inner_removed,
false,
false,
2026 (inv_ctx && rteid - 1 < (Index) inv_ctx->
natoms)
2027 ? inv_ctx->
sub[rteid - 1] : NULL);
2028 if (new_subquery != NULL) {
2030 int *offset = (
int *)palloc(old_targetlist_length *
sizeof(
int));
2031 unsigned varattnoprovsql;
2032 ListCell *cell, *prev;
2034 r->subquery = new_subquery;
2036 if (inner_removed != NULL) {
2037 for (cell = list_head(r->eref->colnames), prev = NULL;
2039 if (inner_removed[i]) {
2043 cell =
my_lnext(r->eref->colnames, prev);
2045 cell = list_head(r->eref->colnames);
2048 cell =
my_lnext(r->eref->colnames, cell);
2052 for (i = 0; i < old_targetlist_length; ++i) {
2054 (i == 0 ? 0 : offset[i - 1]) - (inner_removed[i] ? 1 : 0);
2060 varattnoprovsql = 0;
2061 for (cell = list_head(new_subquery->targetList); cell != NULL;
2062 cell =
my_lnext(new_subquery->targetList, cell)) {
2063 TargetEntry *te = (TargetEntry *)lfirst(cell);
2078 if (cell == NULL && q->setOperations != NULL &&
2079 IsA(q->setOperations, SetOperationStmt) &&
2080 ((SetOperationStmt *)q->setOperations)->op == SETOP_UNION) {
2081 FuncExpr *one_expr = makeNode(FuncExpr);
2082 TargetEntry *one_te;
2085 one_expr->args = NIL;
2086 one_expr->location = -1;
2087 one_te = makeTargetEntry((Expr *)one_expr,
2088 list_length(new_subquery->targetList) + 1,
2090 new_subquery->targetList = lappend(new_subquery->targetList, one_te);
2091 varattnoprovsql = list_length(new_subquery->targetList);
2092 cell = list_tail(new_subquery->targetList);
2096 r->eref->colnames =
list_insert_nth(r->eref->colnames, varattnoprovsql-1,
2100 constants, q, r, rteid, varattnoprovsql));
2103 r->subquery->targetList);
2105 }
else if (r->rtekind == RTE_JOIN) {
2106 if (r->jointype == JOIN_INNER || r->jointype == JOIN_LEFT ||
2107 r->jointype == JOIN_FULL || r->jointype == JOIN_RIGHT) {
2116 }
else if (r->rtekind == RTE_FUNCTION) {
2118 AttrNumber attid = 1;
2120 foreach (lc, r->functions) {
2121 RangeTblFunction *func = (RangeTblFunction *)lfirst(lc);
2123 if (func->funccolcount == 1) {
2124 FuncExpr *expr = (FuncExpr *)func->funcexpr;
2128 constants, q, r, rteid, attid));
2132 "attributes not supported");
2135 attid += func->funccolcount;
2137 }
else if (r->rtekind == RTE_VALUES) {
2139#if PG_VERSION_NUM >= 120000
2140 }
else if (r->rtekind == RTE_RESULT) {
2144#if PG_VERSION_NUM >= 180000
2145 }
else if (r->rtekind == RTE_GROUP) {
2182 Bitmapset *ressortgrouprefs = NULL;
2183 ListCell *cell, *prev;
2184 *removed = (
bool *)palloc(q->targetList->length *
sizeof(
bool));
2186 for (cell = list_head(q->targetList), prev = NULL; cell != NULL;) {
2187 TargetEntry *rt = (TargetEntry *)lfirst(cell);
2188 (*removed)[i] =
false;
2190 if (rt->expr->type == T_Var) {
2191 Var *v = (Var *)rt->expr;
2194 const char *colname;
2197 colname = rt->resname;
2201 RangeTblEntry *r = (RangeTblEntry *)list_nth(q->rtable, v->varno - 1);
2202 colname = strVal(list_nth(r->eref->colnames, v->varattno - 1));
2208 (*removed)[i] =
true;
2211 if (rt->ressortgroupref > 0)
2213 bms_add_member(ressortgrouprefs, rt->ressortgroupref);
2218 if ((*removed)[i]) {
2220 cell =
my_lnext(q->targetList, prev);
2222 cell = list_head(q->targetList);
2225 rt->resno -= nbRemoved;
2227 cell =
my_lnext(q->targetList, cell);
2233 return ressortgrouprefs;
2254 List *evidence = NIL;
2256 ListCell *cell, *prev;
2261 for (cell = list_head(q->targetList), prev = NULL; cell != NULL;) {
2262 TargetEntry *rt = (TargetEntry *)lfirst(cell);
2263 bool is_given =
false;
2269 if (!rt->resjunk && IsA(rt->expr, FuncExpr) &&
2271 args = ((FuncExpr *)rt->expr)->args;
2272 else if (!rt->resjunk && IsA(rt->expr, OpExpr) &&
2274 args = ((OpExpr *)rt->expr)->args;
2277 if (list_length(args) != 1)
2278 provsql_error(
"provsql.given expects exactly one argument");
2280 evidence = lappend(evidence, linitial(args));
2286 cell = prev ?
my_lnext(q->targetList, prev) : list_head(q->targetList);
2288 rt->resno -= nbRemoved;
2290 cell =
my_lnext(q->targetList, cell);
2342 OpExpr *fromOpExpr, Expr *toExpr,
2352 if (
my_lnext(fromOpExpr->args, list_head(fromOpExpr->args))) {
2354 if (IsA(linitial(fromOpExpr->args), Var)) {
2355 v1 = linitial(fromOpExpr->args);
2356 }
else if (IsA(linitial(fromOpExpr->args), RelabelType)) {
2358 RelabelType *rt1 = linitial(fromOpExpr->args);
2359 if (IsA(rt1->arg, Var)) {
2360 v1 = (Var *)rt1->arg;
2365 if (!columns[v1->varno - 1])
2367 first_arg = Int16GetDatum(columns[v1->varno - 1][v1->varattno - 1]);
2369 if (IsA(lsecond(fromOpExpr->args), Var)) {
2370 v2 = lsecond(fromOpExpr->args);
2371 }
else if (IsA(lsecond(fromOpExpr->args), RelabelType)) {
2373 RelabelType *rt2 = lsecond(fromOpExpr->args);
2374 if (IsA(rt2->arg, Var)) {
2375 v2 = (Var *)rt2->arg;
2380 if (!columns[v2->varno - 1])
2382 second_arg = Int16GetDatum(columns[v2->varno - 1][v2->varattno - 1]);
2384 fc = makeNode(FuncExpr);
2386 fc->funcvariadic =
false;
2390 c1 = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int16),
2391 first_arg,
false,
true);
2393 c2 = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int16),
2394 second_arg,
false,
true);
2396 fc->args = list_make3(toExpr, c1, c2);
2418 Node *quals, Expr *result,
2425 if (IsA(quals, OpExpr)) {
2426 oe = (OpExpr *)quals;
2429 else if (IsA(quals, BoolExpr)) {
2430 BoolExpr *be = (BoolExpr *)quals;
2432 if (be->boolop == OR_EXPR || be->boolop == NOT_EXPR) {
2433 provsql_error(
"Boolean operators OR and NOT in a join...on "
2434 "clause are not supported");
2437 foreach (lc2, be->args) {
2438 if (IsA(lfirst(lc2), OpExpr)) {
2439 oe = (OpExpr *)lfirst(lc2);
2464 if (
my_lnext(prov_atts, list_head(prov_atts)) == NULL)
2465 return (Expr *)linitial(prov_atts);
2467 combine = makeNode(FuncExpr);
2469 ArrayExpr *array = makeNode(ArrayExpr);
2472 combine->funcvariadic =
true;
2476 array->elements = prov_atts;
2477 array->location = -1;
2479 combine->args = list_make1(array);
2482 combine->args = prov_atts;
2485 combine->location = -1;
2486 return (Expr *)combine;
2517 Aggref *agg_ref, List *prov_atts,
2520 Expr *rv_arg = ((TargetEntry *)linitial(agg_ref->args))->expr;
2530 wrap = makeNode(FuncExpr);
2533 wrap->args = list_make2(prov_expr, rv_arg);
2534 wrap->location = -1;
2539 te = makeNode(TargetEntry);
2541 te->expr = (Expr *)wrap;
2543 new_agg = makeNode(Aggref);
2544 new_agg->aggfnoid = agg_ref->aggfnoid;
2547 new_agg->aggkind = AGGKIND_NORMAL;
2548 new_agg->aggtranstype = InvalidOid;
2549 new_agg->args = list_make1(te);
2550 new_agg->location = agg_ref->location;
2551#if PG_VERSION_NUM >= 140000
2552 new_agg->aggno = new_agg->aggtransno = -1;
2555 return (Expr *)new_agg;
2579 Aggref *agg_ref, List *prov_atts,
2582 FuncExpr *expr, *expr_s;
2583 Aggref *agg = makeNode(Aggref);
2584 FuncExpr *plus = makeNode(FuncExpr);
2585 TargetEntry *te_inner = makeNode(TargetEntry);
2586 Const *fn = makeNode(Const);
2587 Const *typ = makeNode(Const);
2590 result = linitial(prov_atts);
2592 Oid aggregation_function = agg_ref->aggfnoid;
2606 if (
my_lnext(prov_atts, list_head(prov_atts)) == NULL)
2607 expr = linitial(prov_atts);
2609 expr = makeNode(FuncExpr);
2611 ArrayExpr *array = makeNode(ArrayExpr);
2614 expr->funcvariadic =
true;
2618 array->elements = prov_atts;
2619 array->location = -1;
2621 expr->args = list_make1(array);
2624 expr->args = prov_atts;
2627 expr->location = -1;
2631 expr_s = makeNode(FuncExpr);
2636 if (aggregation_function ==
F_COUNT_)
2638 Const *one = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
2639 sizeof(int32), Int32GetDatum(1),
false,
true);
2640 expr_s->args = list_make2(one, expr);
2652 Expr *arg = ((TargetEntry *)linitial(agg_ref->args))->expr;
2653 CaseExpr *ce = makeNode(CaseExpr);
2654 CaseWhen *cw = makeNode(CaseWhen);
2655 NullTest *nt = makeNode(NullTest);
2657 nt->arg = (Expr *)arg;
2658 nt->nulltesttype = IS_NOT_NULL;
2659 nt->argisrow =
false;
2662 cw->expr = (Expr *)nt;
2663 cw->result = (Expr *)makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
2664 sizeof(int32), Int32GetDatum(1),
false,
2669 ce->casecollid = InvalidOid;
2671 ce->args = list_make1(cw);
2672 ce->defresult = (Expr *)makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
2673 sizeof(int32), Int32GetDatum(0),
false,
2677 expr_s->args = list_make2(ce, expr);
2689 list_make2(((TargetEntry *)linitial(agg_ref->args))->expr, expr);
2692 expr_s->location = -1;
2695 te_inner->resno = 1;
2696 te_inner->expr = (Expr *)expr_s;
2699 agg->args = list_make1(te_inner);
2700 agg->aggkind = AGGKIND_NORMAL;
2702#if PG_VERSION_NUM >= 140000
2703 agg->aggno = agg->aggtransno = -1;
2706 agg->aggargtypes = list_make1_oid(constants->
OID_TYPE_UUID);
2716 if (agg_ref->aggorder != NIL) {
2717 AttrNumber sort_resno = 2;
2719 foreach (lc, agg_ref->args) {
2720 TargetEntry *arg_te = (TargetEntry *)lfirst(lc);
2721 TargetEntry *te_sort;
2722 if (arg_te->ressortgroupref == 0)
2724 te_sort = makeTargetEntry((Expr *)copyObject(arg_te->expr),
2725 sort_resno++, NULL,
true);
2726 te_sort->ressortgroupref = arg_te->ressortgroupref;
2727 agg->args = lappend(agg->args, te_sort);
2729 agg->aggorder = (List *)copyObject((Node *)agg_ref->aggorder);
2735 fn = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
2736 Int32GetDatum(aggregation_function),
false,
true);
2743 typ = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
2744 Int32GetDatum(agg_ref->aggtype),
false,
true);
2747 plus->args = list_make5(fn, typ, agg_ref, agg,
2748 makeConst(BOOLOID, -1, InvalidOid,
sizeof(
bool),
2749 BoolGetDatum(is_scalar),
false,
true));
2750 plus->location = -1;
2752 result = (Expr *)plus;
2799 if (IsA(node, Var) &&
2804 if (IsA(node, FuncExpr) &&
2805 ((FuncExpr *)node)->funcid ==
2830 if (n == NULL || !IsA(n, Const) || ((Const *)n)->constisnull)
2833 getTypeOutputInfo(c->consttype, &outfunc, &isvarlena);
2834 s = OidOutputFunctionCall(outfunc, c->constvalue);
2842 ParseState *p = make_parsestate(NULL);
2843 Node *e = (Node *)make_op(p, list_make1(makeString(pstrdup(op))),
2862 Node *a, *b, *agg_side, *thr;
2867 if (list_length(cmp->args) != 2)
2869 a = (Node *)linitial(cmp->args);
2870 b = (Node *)lsecond(cmp->args);
2878 agg_side = a; thr = b;
2880 agg_side = b; thr = a;
2881 opno = get_commutator(opno);
2882 if (!OidIsValid(opno))
2895 if (peeled == NULL || !IsA(peeled, OpExpr)) {
2899 inner = (OpExpr *)peeled;
2900 iname = get_opname(inner->opno);
2903 nin = list_length(inner->args);
2905 if (nin == 1 && strcmp(iname,
"-") == 0) {
2908 agg_side = (Node *)linitial(inner->args);
2909 }
else if (nin == 2) {
2910 Node *x = (Node *)linitial(inner->args);
2911 Node *y = (Node *)lsecond(inner->args);
2919 if (x_agg) { agg_side = x; c = y; agg_left =
true; }
2920 else { agg_side = y; c = x; agg_left =
false; }
2922 if (strcmp(iname,
"+") == 0) {
2924 }
else if (strcmp(iname,
"-") == 0) {
2931 }
else if (strcmp(iname,
"/") == 0) {
2937 Oid divtype = exprType(peeled);
2939 if (divtype == INT2OID || divtype == INT4OID || divtype == INT8OID)
2946 }
else if (strcmp(iname,
"*") == 0) {
2956 thr_num = coerce_to_target_type(NULL, thr, exprType(thr),
2957 NUMERICOID, -1, COERCION_EXPLICIT,
2958 COERCE_EXPLICIT_CAST, -1);
2959 if (thr_num == NULL)
2972 opno = get_commutator(opno);
2973 if (!OidIsValid(opno))
2978 res = makeNode(OpExpr);
2980 res->opresulttype = BOOLOID;
2981 res->opretset =
false;
2982 res->opcollid = InvalidOid;
2983 res->inputcollid = cmp->inputcollid;
2984 res->location = cmp->location;
2985 res->args = list_make2(agg_side, thr);
3023 opno = opExpr->opno;
3025 for (
unsigned i = 0; i < 2; ++i) {
3026 Node *node = (Node *)lfirst(list_nth_cell(opExpr->args, i));
3027 Node *agg_node = NULL;
3029 if (IsA(node, FuncExpr)) {
3030 FuncExpr *fe = (FuncExpr *)node;
3031 if (fe->funcformat == COERCE_IMPLICIT_CAST ||
3032 fe->funcformat == COERCE_EXPLICIT_CAST) {
3033 if (fe->args->length == 1)
3034 node = lfirst(list_head(fe->args));
3050 if (swapped != NULL &&
3055 if (agg_node != NULL) {
3057 FuncExpr *castToUUID = makeNode(FuncExpr);
3061 castToUUID->args = list_make1(agg_node);
3062 castToUUID->location = -1;
3064 arguments[i] = (Node *)castToUUID;
3073 FuncExpr *oneExpr = makeNode(FuncExpr);
3074 FuncExpr *semimodExpr = makeNode(FuncExpr);
3079 oneExpr->args = NIL;
3080 oneExpr->location = -1;
3085 semimodExpr->args = list_make2((Expr *)node, (Expr *)oneExpr);
3086 semimodExpr->location = -1;
3088 arguments[i] = (Node *)semimodExpr;
3095 opno = get_negator(opno);
3100 oid = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
3101 Int32GetDatum(opno),
false,
true);
3103 cmpExpr = makeNode(FuncExpr);
3106 cmpExpr->args = list_make3(arguments[0], oid, arguments[1]);
3107 cmpExpr->location = opExpr->location;
3126 Aggref *base_arr, Node *V, Node *K,
3127 NullTestType filter) {
3128 Aggref *arr = (Aggref *)copyObject(base_arr);
3129 TargetEntry *te = (TargetEntry *)linitial(arr->args);
3130 NullTest *flt = makeNode(NullTest);
3131 ArrayExpr *empty = makeNode(ArrayExpr);
3132 CoalesceExpr *coal = makeNode(CoalesceExpr);
3133 FuncExpr *plus = makeNode(FuncExpr);
3135 te->expr = (Expr *)copyObject(K);
3139 flt->arg = (Expr *)copyObject(V);
3140 flt->nulltesttype = filter;
3141 flt->argisrow =
false;
3143 arr->aggfilter = (Expr *)flt;
3146 empty->array_collid = InvalidOid;
3148 empty->elements = NIL;
3149 empty->multidims =
false;
3150 empty->location = -1;
3153 coal->coalescecollid = InvalidOid;
3154 coal->args = list_make2(arr, empty);
3155 coal->location = -1;
3159 plus->funcvariadic =
true;
3160 plus->args = list_make1(coal);
3161 plus->location = -1;
3195 Node *arg = (Node *)nt->arg;
3196 FuncExpr *pa, *plusKn;
3203 if (IsA(arg, FuncExpr)) {
3204 FuncExpr *fe = (FuncExpr *)arg;
3205 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
3206 fe->funcformat == COERCE_EXPLICIT_CAST) &&
3207 list_length(fe->args) == 1)
3208 arg = (Node *)linitial(fe->args);
3210 if (!IsA(arg, FuncExpr) ||
3212 provsql_error(
"HAVING IS [NOT] NULL is only supported directly on an "
3213 "aggregate of a provenance-tracked relation");
3214 pa = (FuncExpr *)arg;
3222 is_scalar = DatumGetBool(((Const *)list_nth(pa->args, 4))->constvalue);
3224 Aggref *arr = (Aggref *)list_nth(pa->args, 3);
3227 if (!IsA(arr, Aggref) || list_length(arr->args) != 1)
3228 provsql_error(
"unexpected aggregate shape in HAVING IS [NOT] NULL");
3229 te = (TargetEntry *)linitial(arr->args);
3230 if (!IsA(te->expr, FuncExpr) ||
3232 provsql_error(
"unexpected aggregate shape in HAVING IS [NOT] NULL");
3233 sm = (FuncExpr *)te->expr;
3234 V = (Node *)list_nth(sm->args, 0);
3235 K = (Node *)list_nth(sm->args, 1);
3239 ntt = nt->nulltesttype;
3241 ntt = (ntt == IS_NULL) ? IS_NOT_NULL : IS_NULL;
3246 if (ntt == IS_NOT_NULL) {
3248 FuncExpr *delta = makeNode(FuncExpr);
3251 delta->args = list_make1(plusKn);
3252 delta->location = -1;
3258 FuncExpr *one = makeNode(FuncExpr);
3259 FuncExpr *monus = makeNode(FuncExpr);
3266 monus->args = list_make2(one, plusKn);
3267 monus->location = -1;
3277 FuncExpr *deltaKz = makeNode(FuncExpr);
3278 FuncExpr *times = makeNode(FuncExpr);
3279 ArrayExpr *factors = makeNode(ArrayExpr);
3283 deltaKz->args = list_make1(plusKz);
3284 deltaKz->location = -1;
3287 factors->array_collid = InvalidOid;
3289 factors->elements = list_make2(deltaKz, monus);
3290 factors->multidims =
false;
3291 factors->location = -1;
3295 times->funcvariadic =
true;
3296 times->args = list_make1(factors);
3297 times->location = -1;
3314 Expr *expr,
bool negated) {
3315 FuncExpr *ind = makeNode(FuncExpr);
3317 provsql_error(
"a regular comparison in a probabilistic predicate requires "
3318 "provsql.regular_indicator (schema too old)");
3321 ind->funcretset =
false;
3322 ind->funcvariadic =
false;
3323 ind->funcformat = COERCE_EXPLICIT_CALL;
3324 ind->funccollid = InvalidOid;
3325 ind->inputcollid = InvalidOid;
3326 ind->args = list_make1(negated
3327 ? (Expr *) makeBoolExpr(NOT_EXPR, list_make1(expr), -1)
3347 if(be->boolop == NOT_EXPR) {
3348 Expr *expr = (Expr *) lfirst(list_head(be->args));
3354 ArrayExpr *array = makeNode(ArrayExpr);
3358 array->location = -1;
3360 result = makeNode(FuncExpr);
3362 result->funcvariadic =
true;
3363 result->location = be->location;
3364 result->args = list_make1(array);
3366 if ((be->boolop == AND_EXPR && !negated) || (be->boolop == OR_EXPR && negated))
3368 else if ((be->boolop == AND_EXPR && negated) || (be->boolop == OR_EXPR && !negated))
3373 foreach (lc, be->args) {
3374 Expr *expr = (Expr *)lfirst(lc);
3376 l = lappend(l, arg);
3379 array->elements = l;
3404 if (IsA(expr, BoolExpr))
3406 else if (IsA(expr, OpExpr))
3408 else if (IsA(expr, NullTest))
3411 provsql_error(
"Unknown structure within Boolean expression");
3444 for (
int i = 0; i < 6; ++i) {
3465 RelabelType *rt = makeNode(RelabelType);
3466 rt->arg = (Expr *) operand;
3468 rt->resulttypmod = -1;
3469 rt->resultcollid = InvalidOid;
3470 rt->relabelformat = COERCE_IMPLICIT_CAST;
3502 Oid opno = opExpr->opno;
3503 Node *left = (Node *)linitial(opExpr->args);
3504 Node *right = (Node *)lsecond(opExpr->args);
3507 opno = get_negator(opno);
3509 provsql_error(
"Missing negator for random_variable comparison");
3512 oid_const = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
3513 sizeof(int32), Int32GetDatum(opno),
false,
true);
3515 cmpExpr = makeNode(FuncExpr);
3518 cmpExpr->args = list_make3(
3522 cmpExpr->location = opExpr->location;
3544 if (be->boolop == NOT_EXPR) {
3545 Expr *child = (Expr *)linitial(be->args);
3549 array = makeNode(ArrayExpr);
3552 array->location = -1;
3554 result = makeNode(FuncExpr);
3556 result->funcvariadic =
true;
3557 result->location = be->location;
3558 result->args = list_make1(array);
3560 if ((be->boolop == AND_EXPR && !negated) ||
3561 (be->boolop == OR_EXPR && negated))
3563 else if ((be->boolop == AND_EXPR && negated) ||
3564 (be->boolop == OR_EXPR && !negated))
3567 provsql_error(
"Unknown Boolean operator in random_variable WHERE clause");
3569 foreach (lc, be->args) {
3571 constants, negated);
3572 l = lappend(l, arg);
3574 array->elements = l;
3594 if (IsA(expr, BoolExpr))
3596 if (IsA(expr, OpExpr)) {
3597 OpExpr *opExpr = (OpExpr *)expr;
3601 provsql_error(
"Unsupported sub-expression in random_variable WHERE clause "
3602 "(only Boolean combinations of RV comparisons, optionally "
3603 "mixed with ordinary comparisons, are accepted)");
3619 if (IsA(node, OpExpr)) {
3620 OpExpr *op = (OpExpr *)node;
3653 FuncExpr *ind = makeNode(FuncExpr);
3655 provsql_error(
"conditioning on an ordinary (regular) comparison requires "
3656 "provsql.regular_indicator (schema too old)");
3659 ind->funcretset =
false;
3660 ind->funcvariadic =
false;
3661 ind->funcformat = COERCE_EXPLICIT_CALL;
3662 ind->funccollid = InvalidOid;
3663 ind->inputcollid = InvalidOid;
3664 ind->args = list_make1(negated
3665 ? (Expr *) makeBoolExpr(NOT_EXPR, list_make1(expr), -1)
3671 if (IsA(expr, BoolExpr)) {
3672 BoolExpr *be = (BoolExpr *)expr;
3678 if (be->boolop == NOT_EXPR)
3680 constants, !negated);
3682 array = makeNode(ArrayExpr);
3685 array->location = -1;
3687 result = makeNode(FuncExpr);
3689 result->funcvariadic =
true;
3690 result->location = be->location;
3691 result->args = list_make1(array);
3692 if ((be->boolop == AND_EXPR && !negated) ||
3693 (be->boolop == OR_EXPR && negated))
3698 foreach (lc, be->args)
3700 constants, negated));
3701 array->elements = l;
3705 if (IsA(expr, OpExpr)) {
3706 OpExpr *op = (OpExpr *)expr;
3713 provsql_error(
"The right operand of the conditioning operator | must be a "
3714 "Boolean combination of random_variable or aggregate "
3715 "comparisons (e.g. \"X | (X > 3)\")");
3728 Oid *cond_fn, Oid *result_type,
3746 return OidIsValid(*cond_fn);
3766 if (IsA(node, OpExpr)) {
3767 OpExpr *op = (OpExpr *)node;
3768 Oid cond_fn, result_type;
3772 FuncExpr *gate, *cond;
3773 Expr *pred = (Expr *)llast(op->args);
3780 provsql_error(
"the conditioning operator | needs a predicate with at "
3781 "least one random_variable / aggregate comparison; a "
3782 "purely regular condition is an ordinary filter -- use a "
3783 "WHERE clause instead");
3785 cond = makeNode(FuncExpr);
3786 cond->funcid = cond_fn;
3787 cond->funcresulttype = result_type;
3788 cond->funcretset =
false;
3789 cond->funcvariadic =
false;
3790 cond->funcformat = COERCE_EXPLICIT_CALL;
3791 cond->funccollid = InvalidOid;
3792 cond->inputcollid = InvalidOid;
3794 cond->args = list_make1(gate);
3796 Expr *target = (Expr *)expression_tree_mutator(
3798 cond->args = list_make2(target, gate);
3800 cond->location = op->location;
3801 return (Node *) cond;
3817 q->targetList = (List *)expression_tree_mutator(
3819 if (q->jointree && q->jointree->quals)
3820 q->jointree->quals = expression_tree_mutator(
3823 q->havingQual = expression_tree_mutator(
3840 if (IsA(node, OpExpr)) {
3841 OpExpr *opExpr = (OpExpr *)node;
3845 if (IsA(node, BoolExpr)) {
3846 BoolExpr *be = (BoolExpr *)node;
3848 foreach (lc, be->args) {
3882 if (IsA(expr, OpExpr))
3883 return rv_cmp_index(constants, ((OpExpr *)expr)->opfuncid) >= 0;
3884 if (IsA(expr, BoolExpr)) {
3885 BoolExpr *be = (BoolExpr *)expr;
3887 foreach (lc, be->args) {
3914 const char *desc, Expr *fallback)
3916 FuncCandidateList fcl = FuncnameGetCandidates(
3917 list_make2(makeString(
"provsql"), makeString(
"ucq_joint_provenance")),
3918 2, NIL,
false,
false,
3919#
if PG_VERSION_NUM >= 140000
3930 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
3931 c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
3933 fe = makeNode(FuncExpr);
3934 fe->funcid = fcl->oid;
3936 fe->funcretset =
false;
3937 fe->funcvariadic =
false;
3941 fe->args = list_make2(c, fallback);
3960 const char *desc, Expr *fallback)
3962 FuncCandidateList fcl = FuncnameGetCandidates(
3963 list_make2(makeString(
"provsql"), makeString(
"ucq_mobius_provenance")),
3964 2, NIL,
false,
false,
3965#
if PG_VERSION_NUM >= 140000
3976 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
3977 c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
3979 fe = makeNode(FuncExpr);
3980 fe->funcid = fcl->oid;
3982 fe->funcretset =
false;
3983 fe->funcvariadic =
false;
3984 fe->args = list_make2(c, fallback);
4002 const char *desc, List *head_var_idx,
4003 List *head_exprs, Expr *fallback)
4005 FuncCandidateList fcl = FuncnameGetCandidates(
4006 list_make2(makeString(
"provsql"), makeString(
"ucq_joint_provenance_answer")),
4007 4, NIL,
false,
false,
4008#
if PG_VERSION_NUM >= 140000
4013 Const *desc_c, *hv_c;
4017 int n = list_length(head_var_idx), i;
4021 if (fcl == NULL || head_var_idx == NIL)
4024 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
4025 desc_c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
4028 hd = palloc(n *
sizeof(Datum));
4030 foreach (lc, head_var_idx)
4031 hd[i++] = Int32GetDatum(lfirst_int(lc));
4032 arr = construct_array(hd, n, INT4OID,
sizeof(int32),
true,
TYPALIGN_INT);
4033 hv_c = makeConst(INT4ARRAYOID, -1, InvalidOid, -1,
4034 PointerGetDatum(arr),
false,
false);
4040 vals = makeNode(ArrayExpr);
4041 vals->array_typeid = TEXTARRAYOID;
4042 vals->element_typeid = TEXTOID;
4043 vals->multidims =
false;
4044 vals->elements = NIL;
4045 foreach (lc, head_exprs) {
4046 CoerceViaIO *cio = makeNode(CoerceViaIO);
4047 cio->arg = (Expr *) lfirst(lc);
4048 cio->resulttype = TEXTOID;
4049 cio->resultcollid = DEFAULT_COLLATION_OID;
4050 cio->coerceformat = COERCE_IMPLICIT_CAST;
4052 vals->elements = lappend(vals->elements, (Node *) cio);
4054 vals->location = -1;
4056 fe = makeNode(FuncExpr);
4057 fe->funcid = fcl->oid;
4059 fe->funcretset =
false;
4060 fe->funcvariadic =
false;
4061 fe->args = list_make4(desc_c, hv_c, (Expr *) vals, fallback);
4075 const char *desc, List *head_var_idx,
4076 List *head_exprs, Expr *fallback)
4078 FuncCandidateList fcl = FuncnameGetCandidates(
4079 list_make2(makeString(
"provsql"), makeString(
"ucq_mobius_provenance_answer")),
4080 4, NIL,
false,
false,
4081#
if PG_VERSION_NUM >= 140000
4086 Const *desc_c, *hv_c;
4090 int n = list_length(head_var_idx), i;
4094 if (fcl == NULL || head_var_idx == NIL)
4097 jb = DirectFunctionCall1(jsonb_in, CStringGetDatum(desc));
4098 desc_c = makeConst(JSONBOID, -1, InvalidOid, -1, jb,
false,
false);
4100 hd = palloc(n *
sizeof(Datum));
4102 foreach (lc, head_var_idx)
4103 hd[i++] = Int32GetDatum(lfirst_int(lc));
4104 arr = construct_array(hd, n, INT4OID,
sizeof(int32),
true,
TYPALIGN_INT);
4105 hv_c = makeConst(INT4ARRAYOID, -1, InvalidOid, -1,
4106 PointerGetDatum(arr),
false,
false);
4108 vals = makeNode(ArrayExpr);
4109 vals->array_typeid = TEXTARRAYOID;
4110 vals->element_typeid = TEXTOID;
4111 vals->multidims =
false;
4112 vals->elements = NIL;
4113 foreach (lc, head_exprs) {
4114 CoerceViaIO *cio = makeNode(CoerceViaIO);
4115 cio->arg = (Expr *) lfirst(lc);
4116 cio->resulttype = TEXTOID;
4117 cio->resultcollid = DEFAULT_COLLATION_OID;
4118 cio->coerceformat = COERCE_IMPLICIT_CAST;
4120 vals->elements = lappend(vals->elements, (Node *) cio);
4122 vals->location = -1;
4124 fe = makeNode(FuncExpr);
4125 fe->funcid = fcl->oid;
4127 fe->funcretset =
false;
4128 fe->funcvariadic =
false;
4129 fe->args = list_make4(desc_c, hv_c, (Expr *) vals, fallback);
4142 FuncCandidateList fcl = FuncnameGetCandidates(
4143 list_make2(makeString(
"provsql"), makeString(
"mobius_or_null")),
4144 1, NIL,
false,
false,
4145#
if PG_VERSION_NUM >= 140000
4154 fe = makeNode(FuncExpr);
4155 fe->funcid = fcl->oid;
4157 fe->funcretset =
false;
4158 fe->funcvariadic =
false;
4159 fe->args = list_make1(mobius_call);
4184 Expr *mobius_call, Expr *joint_call,
4190 if (mobius_call == NULL)
4191 return (joint_call != NULL) ? joint_call : lineage;
4195 ce = makeNode(CoalesceExpr);
4197 ce->coalescecollid = InvalidOid;
4200 ce->args = list_make2(first, (joint_call != NULL) ? joint_call : lineage);
4254 List *prov_atts,
bool aggregation,
4255 bool group_by_rewrite,
4257 int nbcols,
bool wrap_assumed,
4258 bool in_boolean_rewrite,
4259 const char *inv_cert) {
4264 char *jw_desc = NULL;
4265 bool jw_all_exist =
false;
4266 List *jw_head_idx = NIL;
4267 List *jw_head_exprs = NIL;
4280 op !=
SR_PLUS && (aggregation || group_by_rewrite) &&
4281 !in_boolean_rewrite && inv_cert == NULL)
4283 &jw_head_idx, &jw_head_exprs);
4286 result = linitial(prov_atts);
4288 if (
my_lnext(prov_atts, list_head(prov_atts)) == NULL) {
4289 result = linitial(prov_atts);
4291 FuncExpr *expr = makeNode(FuncExpr);
4293 ArrayExpr *array = makeNode(ArrayExpr);
4296 expr->funcvariadic =
true;
4300 array->elements = prov_atts;
4301 array->location = -1;
4303 expr->args = list_make1(array);
4306 expr->args = prov_atts;
4309 expr->location = -1;
4311 result = (Expr *)expr;
4314 if (group_by_rewrite || aggregation) {
4315 Aggref *agg = makeNode(Aggref);
4316 FuncExpr *plus = makeNode(FuncExpr);
4317 TargetEntry *te_inner = makeNode(TargetEntry);
4321 te_inner->resno = 1;
4322 te_inner->expr = (Expr *)result;
4326 agg->args = list_make1(te_inner);
4327 agg->aggkind = AGGKIND_NORMAL;
4329#if PG_VERSION_NUM >= 140000
4330 agg->aggno = agg->aggtransno = -1;
4333 agg->aggargtypes = list_make1_oid(constants->
OID_TYPE_UUID);
4336 plus->args = list_make1(agg);
4338 plus->location = -1;
4340 result = (Expr *)plus;
4353 bool lift_having = q->havingQual != NULL &&
4356 if (aggregation && !lift_having) {
4357 if (q->groupClause == NIL && q->groupingSets == NIL) {
4368 FuncExpr *oneExpr = makeNode(FuncExpr);
4371 oneExpr->args = NIL;
4372 oneExpr->location = -1;
4373 result = (Expr *)oneExpr;
4375 FuncExpr *deltaExpr = makeNode(FuncExpr);
4379 deltaExpr->args = list_make1(result);
4381 deltaExpr->location = -1;
4383 result = (Expr *)deltaExpr;
4389 q->havingQual = NULL;
4399 foreach (lc, q->jointree->fromlist) {
4400 if (IsA(lfirst(lc), JoinExpr)) {
4401 JoinExpr *je = (JoinExpr *)lfirst(lc);
4413 ArrayExpr *array = makeNode(ArrayExpr);
4414 FuncExpr *fe = makeNode(FuncExpr);
4415 bool projection =
false;
4429 int *prov_offset = (
int *)palloc0((q->rtable->length + 1) *
sizeof(
int));
4434 fe->funcvariadic =
true;
4440 array->elements = NIL;
4441 array->location = -1;
4443 for (r = 1; r <= (Index)q->rtable->length; ++r) {
4444 prov_offset[r] = cum;
4446 RangeTblEntry *rte_r = (RangeTblEntry *)list_nth(q->rtable, r-1);
4447 int ncols = list_length(rte_r->eref->colnames);
4448 bool is_prov =
false;
4451 for (k = 0; k < ncols; ++k) {
4452 if (columns[r-1][k] == -1) is_prov =
true;
4453 else if (columns[r-1][k] > 0) nb_user++;
4455 if (is_prov) cum += nb_user;
4459 foreach (lc_v, q->targetList) {
4460 TargetEntry *te_v = (TargetEntry *)lfirst(lc_v);
4461 if (IsA(te_v->expr, Var)) {
4462 Var *vte_v = (Var *)te_v->expr;
4463 RangeTblEntry *rte_v =
4464 (RangeTblEntry *)lfirst(list_nth_cell(q->rtable, vte_v->varno - 1));
4466#if PG_VERSION_NUM >= 180000
4467 if (rte_v->rtekind == RTE_GROUP) {
4468 Expr *ge = lfirst(list_nth_cell(rte_v->groupexprs, vte_v->varattno - 1));
4470 Var *v = (Var *) ge;
4471 value_v = columns[v->varno - 1] ?
4472 columns[v->varno - 1][v->varattno - 1] : 0;
4474 Const *ce = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
4475 sizeof(int32), Int32GetDatum(0),
false,
true);
4477 array->elements = lappend(array->elements, ce);
4482 if (rte_v->rtekind != RTE_JOIN) {
4483 if (rte_v->rtekind == RTE_RELATION && columns[vte_v->varno - 1]) {
4487 bool is_prov =
false;
4488 int ncols_rte = list_length(rte_v->eref->colnames);
4489 for (
int k = 0; k < ncols_rte; k++) {
4490 if (columns[vte_v->varno - 1][k] == -1) {
4496 int raw = columns[vte_v->varno - 1][vte_v->varattno - 1];
4504 value_v = (raw == -1) ? -1
4505 : (int)vte_v->varattno
4506 + prov_offset[vte_v->varno];
4515 sizeof(int32), Int32GetDatum(0),
false,
true);
4516 array->elements = lappend(array->elements, ce);
4524 value_v = columns[vte_v->varno - 1] ?
4525 columns[vte_v->varno - 1][vte_v->varattno - 1] : 0;
4528 Var *jav_v = (Var *)lfirst(
4529 list_nth_cell(rte_v->joinaliasvars, vte_v->varattno - 1));
4530 if (jav_v && IsA(jav_v, Var) && columns[jav_v->varno - 1]) {
4531 RangeTblEntry *jrte_v = (RangeTblEntry *)lfirst(
4532 list_nth_cell(q->rtable, jav_v->varno - 1));
4533 if (jrte_v->rtekind == RTE_RELATION) {
4536 bool is_prov =
false;
4537 int ncols_jrte = list_length(jrte_v->eref->colnames);
4538 for (
int k = 0; k < ncols_jrte; k++) {
4539 if (columns[jav_v->varno - 1][k] == -1) {
4545 int raw = columns[jav_v->varno - 1][jav_v->varattno - 1];
4546 value_v = (raw == -1) ? -1
4547 : (int)jav_v->varattno
4548 + prov_offset[jav_v->varno];
4552 sizeof(int32), Int32GetDatum(0),
false,
true);
4553 array->elements = lappend(array->elements, ce);
4558 value_v = columns[jav_v->varno - 1][jav_v->varattno - 1];
4568 makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
sizeof(int32),
4569 Int32GetDatum(value_v),
false,
true);
4571 array->elements = lappend(array->elements, ce);
4573 if (value_v != ++nb_column)
4580 Const *ce = makeConst(constants->
OID_TYPE_INT, -1, InvalidOid,
4581 sizeof(int32), Int32GetDatum(0),
false,
true);
4583 array->elements = lappend(array->elements, ce);
4588 if (nb_column != nbcols)
4592 fe->args = list_make2(result, array);
4593 result = (Expr *)fe;
4618 if (inv_cert != NULL &&
4633 if (jw_desc != NULL && jw_all_exist) {
4649 }
else if (jw_desc != NULL && jw_head_idx != NIL && inv_cert == NULL) {
4658 jw_head_exprs, result)
4662 jw_head_exprs, result)
4674#if PG_VERSION_NUM >= 180000
4676 Index group_rtindex;
4678} resolve_group_rte_ctx;
4681resolve_group_rte_vars_mutator(Node *node,
void *raw_ctx) {
4682 resolve_group_rte_ctx *ctx = (resolve_group_rte_ctx *)raw_ctx;
4685 if (IsA(node, Var)) {
4686 Var *v = (Var *)node;
4687 if (v->varno == ctx->group_rtindex) {
4688 Node *resolved = copyObject(list_nth(ctx->groupexprs, v->varattno - 1));
4689#if PG_VERSION_NUM >= 160000
4695 if (IsA(resolved, Var))
4696 ((Var *)resolved)->varnullingrels = NULL;
4701 return expression_tree_mutator(node, resolve_group_rte_vars_mutator, raw_ctx);
4719 resolve_group_rte_ctx grp_ctx;
4725 if (!q->hasGroupRTE)
4728 foreach (lc, q->rtable) {
4729 RangeTblEntry *r = (RangeTblEntry *) lfirst(lc);
4730 if (r->rtekind == RTE_GROUP) {
4731 grp_ctx.group_rtindex = idx;
4732 grp_ctx.groupexprs = r->groupexprs;
4743 q->rtable = list_truncate(q->rtable, rte_len);
4744 q->hasGroupRTE =
false;
4746 foreach (lc, q->targetList) {
4747 TargetEntry *te = (TargetEntry *) lfirst(lc);
4748 te->expr = (Expr *) resolve_group_rte_vars_mutator(
4749 (Node *) te->expr, &grp_ctx);
4751 if (q->jointree && q->jointree->quals)
4752 q->jointree->quals = resolve_group_rte_vars_mutator(
4753 q->jointree->quals, &grp_ctx);
4763 q->havingQual = resolve_group_rte_vars_mutator(q->havingQual, &grp_ctx);
4786 List *groupby_tes) {
4791 int resno = 1, sgref = 1;
4793 inner = copyObject(q);
4795 inner->hasAggs =
false;
4796 inner->sortClause = NIL;
4797 inner->limitCount = NULL;
4798 inner->limitOffset = NULL;
4799 inner->distinctClause = NIL;
4800 inner->hasDistinctOn =
false;
4801 inner->havingQual = NULL;
4805 TargetEntry *kte = makeNode(TargetEntry);
4806 SortGroupClause *sgc = makeNode(SortGroupClause);
4808 kte->expr = copyObject(key_expr);
4809 kte->resno = resno++;
4810 kte->resname =
"key";
4811 sgc->tleSortGroupRef = kte->ressortgroupref = sgref++;
4812 get_sort_group_operators(exprType((Node *)kte->expr),
true,
true,
false,
4813 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
4814 new_gc = list_make1(sgc);
4815 new_tl = list_make1(kte);
4819 foreach (lc, groupby_tes) {
4820 TargetEntry *gyte = copyObject((TargetEntry *)lfirst(lc));
4821 SortGroupClause *sgc = makeNode(SortGroupClause);
4823 gyte->resno = resno++;
4824 gyte->resjunk =
false;
4825 sgc->tleSortGroupRef = gyte->ressortgroupref = sgref++;
4826 get_sort_group_operators(exprType((Node *)gyte->expr),
true,
true,
false,
4827 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
4828 new_gc = lappend(new_gc, sgc);
4829 new_tl = lappend(new_tl, gyte);
4832 inner->targetList = new_tl;
4833 inner->groupClause = new_gc;
4856 Query *inner,
int n_gb,
4858 Query *outer = makeNode(Query);
4859 RangeTblEntry *rte = makeNode(RangeTblEntry);
4860 Alias *alias = makeNode(Alias), *eref = makeNode(Alias);
4861 RangeTblRef *rtr = makeNode(RangeTblRef);
4862 FromExpr *jt = makeNode(FromExpr);
4863 List *new_tl = NIL, *new_gc = NIL;
4865 int resno = 1, sgref = 1;
4866 int inner_len = list_length(inner->targetList);
4870 alias->aliasname = eref->aliasname =
"d";
4871 eref->colnames = NIL;
4872 foreach (lc, inner->targetList) {
4873 TargetEntry *te = lfirst(lc);
4874 eref->colnames = lappend(eref->colnames,
4875 makeString(te->resname ? pstrdup(te->resname) :
""));
4879 rte->rtekind = RTE_SUBQUERY;
4880 rte->subquery = inner;
4881 rte->inFromCl =
true;
4882#if PG_VERSION_NUM < 160000
4883 rte->requiredPerms = ACL_SELECT;
4887 jt->fromlist = list_make1(rtr);
4889 outer->commandType = CMD_SELECT;
4890 outer->canSetTag =
true;
4891 outer->rtable = list_make1(rte);
4892 outer->jointree = jt;
4893 outer->hasAggs =
true;
4897 TargetEntry *agg_te = copyObject(orig_agg_te);
4898 Aggref *ar = (Aggref *)agg_te->expr;
4899 Var *key_var = makeNode(Var);
4900 TargetEntry *arg_te = makeNode(TargetEntry);
4903 key_var->varattno = 1;
4904 key_var->vartype = linitial_oid(ar->aggargtypes);
4905 key_var->varcollid = exprCollation((Node *)((TargetEntry *)linitial(ar->args))->expr);
4906 key_var->vartypmod = -1;
4907 key_var->location = -1;
4909 arg_te->expr = (Expr *)key_var;
4911 ar->args = list_make1(arg_te);
4912 ar->aggdistinct = NIL;
4913 agg_te->resno = resno++;
4914 new_tl = list_make1(agg_te);
4918 for (attno = inner_len - n_gb + 1; attno <= inner_len; attno++) {
4919 TargetEntry *inner_te = list_nth(inner->targetList, attno - 1);
4920 Var *gb_var = makeNode(Var);
4921 TargetEntry *gb_te = makeNode(TargetEntry);
4922 SortGroupClause *sgc = makeNode(SortGroupClause);
4925 gb_var->varattno = attno;
4926 gb_var->vartype = exprType((Node *)inner_te->expr);
4927 gb_var->varcollid = exprCollation((Node *)inner_te->expr);
4928 gb_var->vartypmod = -1;
4929 gb_var->location = -1;
4931 gb_te->resno = resno++;
4932 gb_te->expr = (Expr *)gb_var;
4933 gb_te->resname = inner_te->resname;
4935 sgc->tleSortGroupRef = gb_te->ressortgroupref = sgref++;
4936 sgc->nulls_first =
false;
4937 get_sort_group_operators(gb_var->vartype,
true,
true,
false,
4938 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
4939 new_gc = lappend(new_gc, sgc);
4940 new_tl = lappend(new_tl, gb_te);
4943 outer->targetList = new_tl;
4944 outer->groupClause = new_gc;
4963 if (IsA(node, Aggref)) {
4964 Aggref *ar = (Aggref *) node;
4965 if (list_length(ar->aggdistinct) > 0)
4989 if (IsA(node, Aggref)) {
4990 Aggref *ar = (Aggref *) node;
4991 if (list_length(ar->aggdistinct) > 0) {
4993 Var *v = makeNode(Var);
4996 v->vartype = ar->aggtype;
4998 v->varcollid = ar->aggcollid;
5029 List *distinct_agg_tes = NIL;
5030 List *groupby_tes = NIL;
5034#if PG_VERSION_NUM >= 180000
5054 foreach (lc, q->targetList) {
5055 TargetEntry *te = lfirst(lc);
5056 if (IsA(te->expr, Aggref)) {
5057 Aggref *ar = (Aggref *)te->expr;
5058 if (list_length(ar->aggdistinct) > 0)
5059 distinct_agg_tes = lappend(distinct_agg_tes, te);
5061 (
void *)constants)) {
5066 TargetEntry *te_copy = copyObject(te);
5067 te_copy->resjunk =
false;
5068 groupby_tes = lappend(groupby_tes, te_copy);
5075 if (q->havingQual != NULL)
5078 if (distinct_agg_tes == NIL && hctx.
aggs == NIL)
5082 int n_having = list_length(hctx.
aggs);
5083 int n_aggs = list_length(distinct_agg_tes) + n_having;
5084 int n_gb = list_length(groupby_tes);
5085 List *outer_queries = NIL;
5102 foreach (lc, distinct_agg_tes) {
5103 TargetEntry *agg_te = lfirst(lc);
5104 Aggref *ar = (Aggref *)agg_te->expr;
5105 if(list_length(ar->args) != 1)
5106 provsql_error(
"AGG(DISTINCT) with more than one argument is not supported");
5108 Expr *key_expr = (Expr *)((TargetEntry *)linitial(ar->args))->expr;
5111 outer_queries = lappend(outer_queries, outer);
5118 foreach (lc, hctx.
aggs) {
5119 Aggref *ar = lfirst(lc);
5120 if(list_length(ar->args) != 1)
5121 provsql_error(
"AGG(DISTINCT) with more than one argument is not supported");
5123 TargetEntry *syn = makeNode(TargetEntry);
5124 Expr *key_expr = (Expr *)((TargetEntry *)linitial(ar->args))->expr;
5127 syn->expr = (Expr *) copyObject(ar);
5130 outer_queries = lappend(outer_queries, outer);
5142 int rtable_base = list_length(q->rtable);
5144 foreach (lc, outer_queries) {
5145 Query *oq = lfirst(lc);
5146 RangeTblEntry *rte = makeNode(RangeTblEntry);
5147 Alias *alias = makeNode(Alias), *eref = makeNode(Alias);
5151 snprintf(buf,
sizeof(buf),
"d%d", i + 1);
5152 alias->aliasname = eref->aliasname = pstrdup(buf);
5153 eref->colnames = NIL;
5154 foreach (lc2, oq->targetList) {
5155 TargetEntry *te = lfirst(lc2);
5156 eref->colnames = lappend(eref->colnames,
5157 makeString(te->resname ? pstrdup(te->resname) :
""));
5161 rte->rtekind = RTE_SUBQUERY;
5163 rte->inFromCl =
true;
5164#if PG_VERSION_NUM < 160000
5165 rte->requiredPerms = ACL_SELECT;
5167 q->rtable = lappend(q->rtable, rte);
5174 FromExpr *jt = q->jointree;
5175 List *from_list = jt->fromlist;
5176 List *where_args = NIL;
5178 for (i = rtable_base + 1; i <= rtable_base + n_aggs; i++) {
5179 RangeTblRef *rtr = makeNode(RangeTblRef);
5184 from_list = lappend(from_list, rtr);
5187 foreach(lc2, groupby_tes) {
5188 TargetEntry *gb_te = lfirst(lc2);
5189 int gb_attno = ++j + 1;
5190 Oid ytype = exprType((Node *)gb_te->expr);
5192 Operator opInfo = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
5193 Form_pg_operator opform;
5194 OpExpr *oe = makeNode(OpExpr);
5195 Expr *le = copyObject(gb_te->expr);
5196 Var *rv = makeNode(Var);
5197 Oid collation=exprCollation((Node*) le);
5199 if (!HeapTupleIsValid(opInfo))
5200 provsql_error(
"could not find equality operator for type %u",
5202 opform = (Form_pg_operator)GETSTRUCT(opInfo);
5205 oe->opfuncid = opform->oprcode;
5206 oe->opresulttype = opform->oprresult;
5207 oe->opcollid = InvalidOid;
5208 oe->inputcollid = collation;
5210 ReleaseSysCache(opInfo);
5212 rv->varno = i; rv->varattno = gb_attno;
5213 rv->vartype = ytype; rv->varcollid = collation;
5214 rv->vartypmod = -1; rv->location = -1;
5216 oe->args = list_make2(le, rv);
5217 where_args = lappend(where_args, oe);
5221 if (list_length(where_args) == 0) {
5223 }
else if (list_length(where_args) == 1) {
5224 jt->quals = linitial(where_args);
5226 BoolExpr *be = makeNode(BoolExpr);
5227 be->boolop = AND_EXPR;
5228 be->args = where_args;
5230 jt->quals = (Node *)be;
5237 int agg_idx = rtable_base + 1;
5240 foreach (lc2, q->targetList) {
5241 TargetEntry *te = lfirst(lc2);
5243 if (IsA(te->expr, Aggref) &&
5244 ((Aggref *)te->expr)->aggdistinct != NIL) {
5245 Var *v = makeNode(Var);
5246 v->varno = agg_idx++;
5250 te->expr = (Expr*)v;
5261 hrc.
next_rtindex = rtable_base + (n_aggs - n_having) + 1;
5295 if (IsA(node, Aggref)) {
5296 Aggref *ar_v = (Aggref *)node;
5315 Const *typ_const = (Const *)lsecond(prov_agg->args);
5316 Oid target_type = DatumGetObjectId(typ_const->constvalue);
5317 CoercionPathType pathtype;
5320 pathtype = find_coercion_pathway(target_type,
5322 COERCION_EXPLICIT, &castfuncid);
5323 if (pathtype == COERCION_PATH_FUNC && OidIsValid(castfuncid)) {
5324 FuncExpr *cast = makeNode(FuncExpr);
5325 cast->funcid = castfuncid;
5326 cast->funcresulttype = target_type;
5327 cast->funcretset =
false;
5328 cast->funcvariadic =
false;
5329 cast->funcformat = COERCE_IMPLICIT_CAST;
5330 cast->args = list_make1(prov_agg);
5331 cast->location = -1;
5332 return (Node *)cast;
5335 provsql_error(
"no cast from agg_token to %s for arithmetic on aggregate",
5336 format_type_be(target_type));
5337 return (Node *)prov_agg;
5350 CoercionPathType pathtype;
5354 COERCION_EXPLICIT, &castfuncid);
5355 if (pathtype == COERCION_PATH_FUNC && OidIsValid(castfuncid)) {
5356 FuncExpr *cast = makeNode(FuncExpr);
5357 cast->funcid = castfuncid;
5358 cast->funcresulttype = target_type;
5359 cast->funcretset =
false;
5360 cast->funcvariadic =
false;
5361 cast->funcformat = COERCE_IMPLICIT_CAST;
5362 cast->args = list_make1(arg);
5363 cast->location = -1;
5364 return (Node *)cast;
5367 provsql_error(
"no cast from agg_token to %s for arithmetic on aggregate",
5368 format_type_be(target_type));
5389 Form_pg_proc procForm;
5393 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(parent_funcid));
5394 if (!HeapTupleIsValid(tp))
5396 procForm = (Form_pg_proc) GETSTRUCT(tp);
5400 Node *arg = lfirst(lc);
5411 Oid formal_type = procForm->proargtypes.values[i];
5414 !IsPolymorphicType(formal_type)) {
5415 if (IsA(arg, FuncExpr) &&
5425 ReleaseSysCache(tp);
5438 if (n != NULL && IsA(n, FuncExpr)) {
5439 FuncExpr *fe = (FuncExpr *)n;
5440 if ((fe->funcformat == COERCE_IMPLICIT_CAST ||
5441 fe->funcformat == COERCE_EXPLICIT_CAST) &&
5442 list_length(fe->args) == 1) {
5443 n = (Node *)linitial(fe->args);
5446 }
else if (n != NULL && IsA(n, RelabelType)) {
5447 n = (Node *)((RelabelType *)n)->arg;
5471 int nargs = list_length(op->args);
5472 Node *l, *r, *lp, *rp;
5476 if (nargs < 1 || nargs > 2)
5478 opname = get_opname(op->opno);
5481 is_arith = strcmp(opname,
"+") == 0 || strcmp(opname,
"-") == 0 ||
5482 strcmp(opname,
"*") == 0 || strcmp(opname,
"/") == 0;
5489 l = (Node *)linitial(op->args);
5490 r = (Node *)lsecond(op->args);
5493 r = (Node *)linitial(op->args);
5512 pstate = make_parsestate(NULL);
5513 newop = make_op(pstate, list_make1(makeString(opname)), l, r, NULL, -1);
5514 free_parsestate(pstate);
5516 return (Node *)newop;
5546 if (IsA(result, OpExpr)) {
5547 OpExpr *op = (OpExpr *)result;
5549 if (swapped != NULL)
5553 }
else if (IsA(result, FuncExpr)) {
5554 FuncExpr *fe = (FuncExpr *)result;
5579 char *opname = get_opname(op->opno);
5580 int nargs = list_length(op->args);
5581 Node *l = NULL, *r = NULL, *aggn = NULL, *cn = NULL, *old_arg, *new_arg = NULL;
5584 bool agg_left =
true, plus, minus, times;
5585 bool is_sum, is_avg, is_min, is_max;
5589 plus = strcmp(opname,
"+") == 0;
5590 minus = strcmp(opname,
"-") == 0;
5591 times = strcmp(opname,
"*") == 0;
5592 if (!(plus || minus || times))
5599 }
else if (nargs == 2) {
5602 if (IsA(l, Aggref) && IsA(r, Const)) { aggn = l; cn = r; agg_left =
true; }
5603 else if (IsA(r, Aggref) && IsA(l, Const)) { aggn = r; cn = l; agg_left =
false; }
5608 if (!IsA(aggn, Aggref))
5610 ar = (Aggref *)aggn;
5613 if (ar->aggstar || list_length(ar->args) != 1 ||
5614 ar->aggdistinct != NIL || ar->aggfilter != NULL || ar->aggorder != NIL)
5620 aggnm = get_func_name(ar->aggfnoid);
5623 is_sum = strcmp(aggnm,
"sum") == 0; is_avg = strcmp(aggnm,
"avg") == 0;
5624 is_min = strcmp(aggnm,
"min") == 0; is_max = strcmp(aggnm,
"max") == 0;
5626 if (!(is_sum || is_avg || is_min || is_max))
5629 old_arg = (Node *)((TargetEntry *)linitial(ar->args))->expr;
5632 if (is_sum || is_avg)
5635 if (is_sum || is_avg)
5636 new_arg = agg_left ?
build_binop(
"*", old_arg, cn)
5639 if (is_avg || is_min || is_max)
5640 new_arg = agg_left ?
build_binop(
"+", old_arg, cn)
5644 if (is_avg || is_min || is_max)
5651 if (new_arg == NULL)
5655 if (exprType(new_arg) != exprType(old_arg))
5658 newar = (Aggref *)copyObject(ar);
5659 ((TargetEntry *)linitial(newar->args))->expr = (Expr *)new_arg;
5660 return (Node *)newar;
5668 if (IsA(node, OpExpr)) {
5691 Query *q, List *prov_atts,
5697 bool is_scalar = (q->groupClause == NIL && q->groupingSets == NIL);
5705 QTW_DONT_COPY_QUERY | QTW_IGNORE_RT_SUBQUERIES);
5708 QTW_DONT_COPY_QUERY | QTW_IGNORE_RT_SUBQUERIES);
5715 foreach(lc, q->targetList) {
5716 TargetEntry *te = (TargetEntry *)lfirst(lc);
5717 if (te->expr == NULL)
5720 if (IsA(te->expr, FuncExpr) &&
5739 TargetEntry *newte = makeNode(TargetEntry);
5740 bool inserted =
false;
5747 RangeTblEntry *rte = list_nth(q->rtable, ((Var *)
provenance)->varno - 1);
5748 newte->resorigtbl = rte->relid;
5749 newte->resorigcol = ((Var *)
provenance)->varattno;
5753 for (ListCell *cell = list_head(q->targetList); cell != NULL;) {
5754 TargetEntry *te = (TargetEntry *)lfirst(cell);
5761 newte->resno = resno;
5763 cell = list_nth_cell(q->targetList, resno);
5764 te = (TargetEntry *)lfirst(cell);
5771 cell =
my_lnext(q->targetList, cell);
5775 newte->resno = resno + 1;
5776 q->targetList = lappend(q->targetList, newte);
5804 if (IsA(node, Aggref))
5821 if (IsA(node, Aggref)) {
5834 if (IsA(node, FuncExpr)) {
5835 FuncExpr *f = (FuncExpr *)node;
5840 "applying an SQL aggregate on top of a ProvSQL-introduced "
5841 "aggregation is not supported: the inner provenance() would "
5842 "be substituted with an expression containing an aggregate, "
5843 "producing a nested same-level aggregate that PostgreSQL "
5844 "rejects. Evaluate the per-row provenance in a subquery "
5845 "and aggregate the resulting scalar outside, or drop the "
5846 "surrounding aggregate.");
5848 return (Node *)copyObject(context->
provsql);
5850 }
else if (IsA(node, RangeTblEntry) || IsA(node, RangeTblFunction)) {
5882 QTW_DONT_COPY_QUERY | QTW_IGNORE_RT_SUBQUERIES);
5899 Bitmapset *already_in_group_by = NULL;
5901 foreach (lc, q->groupClause) {
5902 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc);
5903 already_in_group_by =
5904 bms_add_member(already_in_group_by, sgc->tleSortGroupRef);
5907 foreach (lc, q->distinctClause) {
5908 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc);
5909 if (!bms_is_member(sgc->tleSortGroupRef, already_in_group_by)) {
5910 q->groupClause = lappend(q->groupClause, sgc);
5914 q->distinctClause = NULL;
5937 if (!q->distinctClause)
5939 if (q->hasDistinctOn)
5941 else if (q->hasAggs)
5942 provsql_error(
"DISTINCT on aggregate results not supported");
5943 else if (list_length(q->distinctClause) < list_length(q->targetList))
5944 provsql_error(
"Inconsistent DISTINCT and GROUP BY clauses not "
5962 const Bitmapset *removed_sortgrouprefs) {
5963 List **lists[3] = {&q->groupClause, &q->distinctClause, &q->sortClause};
5966 for (i = 0; i < 3; ++i) {
5967 ListCell *cell, *prev;
5969 for (cell = list_head(*lists[i]), prev = NULL; cell != NULL;) {
5970 SortGroupClause *sgc = (SortGroupClause *)lfirst(cell);
5971 if (bms_is_member(sgc->tleSortGroupRef, removed_sortgrouprefs)) {
5977 cell = list_head(*lists[i]);
5999 SetOperationStmt *so = (SetOperationStmt *)q->setOperations;
6000 List **lists[3] = {&so->colTypes, &so->colTypmods, &so->colCollations};
6003 for (i = 0; i < 3; ++i) {
6004 ListCell *cell, *prev;
6007 for (cell = list_head(*lists[i]), prev = NULL, j = 0; cell != NULL; ++j) {
6014 cell = list_head(*lists[i]);
6040 Query *new_query = makeNode(Query);
6041 RangeTblEntry *rte = makeNode(RangeTblEntry);
6042 FromExpr *jointree = makeNode(FromExpr);
6043 RangeTblRef *rtr = makeNode(RangeTblRef);
6045 SetOperationStmt *stmt = (SetOperationStmt *)q->setOperations;
6048 int sortgroupref = 0;
6056 rte->rtekind = RTE_SUBQUERY;
6058 rte->eref = copyObject(((RangeTblEntry *)linitial(q->rtable))->eref);
6059 rte->inFromCl =
true;
6060#if PG_VERSION_NUM < 160000
6063 rte->requiredPerms = ACL_SELECT;
6067 jointree->fromlist = list_make1(rtr);
6069 new_query->commandType = CMD_SELECT;
6070 new_query->canSetTag =
true;
6071 new_query->rtable = list_make1(rte);
6072 new_query->jointree = jointree;
6073 new_query->targetList = copyObject(q->targetList);
6075 if (new_query->targetList) {
6076 foreach (lc, new_query->targetList) {
6077 TargetEntry *te = (TargetEntry *)lfirst(lc);
6078 SortGroupClause *sgc = makeNode(SortGroupClause);
6080 sgc->tleSortGroupRef = te->ressortgroupref = ++sortgroupref;
6082 get_sort_group_operators(exprType((Node *)te->expr),
false,
true,
false,
6083 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
6085 new_query->groupClause = lappend(new_query->groupClause, sgc);
6088 GroupingSet *gs = makeNode(GroupingSet);
6089 gs->kind = GROUPING_SET_EMPTY;
6092 new_query->groupingSets = list_make1(gs);
6116 if (IsA(node, FuncExpr)) {
6117 FuncExpr *f = (FuncExpr *)node;
6142 Bitmapset *group_refs = NULL;
6143 foreach (lc, q->groupClause) {
6144 SortGroupClause *sgc = (SortGroupClause *)lfirst(lc);
6145 group_refs = bms_add_member(group_refs, sgc->tleSortGroupRef);
6148 foreach (lc, q->targetList) {
6149 TargetEntry *te = (TargetEntry *)lfirst(lc);
6150 if (te->ressortgroupref > 0 &&
6151 bms_is_member(te->ressortgroupref, group_refs)) {
6153 (
void *)constants)) {
6157#if PG_VERSION_NUM >= 180000
6160 if(IsA(te->expr, Var)) {
6161 Var *v = (Var *) te->expr;
6162 RangeTblEntry *r = (RangeTblEntry *)list_nth(q->rtable, v->varno - 1);
6163 if(r->rtekind == RTE_GROUP)
6165 (
void *)constants)) {
6198 if (IsA(node, OpExpr)) {
6199 OpExpr *op = (OpExpr *)node;
6204 if (IsA(node, FuncExpr)) {
6205 FuncExpr *f = (FuncExpr *)node;
6210 if (IsA(node, SubLink)) {
6211 SubLink *sl = (SubLink *)node;
6217 if (IsA(node, Query))
6268 return sl != NULL && sl->subselect && IsA(sl->subselect, Query) &&
6286 TargetEntry *only = NULL;
6288 if (sub == NULL || !IsA(sub, Query))
6290 foreach (lc, sub->targetList) {
6291 TargetEntry *te = (TargetEntry *)lfirst(lc);
6298 return only != NULL && IsA(only->expr, FuncExpr) &&
6307 if (IsA(node, SubLink)) {
6308 SubLink *sl = (SubLink *)node;
6309 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
6310 IsA(sl->subselect, Query) &&
6312 (Query *)sl->subselect))
6314 return expression_tree_walker((Node *)sl->testexpr,
6317 if (IsA(node, Query))
6331 if (q->havingQual &&
6341 if (IsA(node, SubLink)) {
6342 SubLink *sl = (SubLink *)node;
6343 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
6344 IsA(sl->subselect, Query) &&
6347 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
6348 IsA(sl->subselect, Query)) {
6349 Query *sub = (Query *)sl->subselect;
6350 if (!sub->hasAggs && !sub->groupClause && !sub->groupingSets &&
6351 !sub->distinctClause && !sub->setOperations && !sub->hasWindowFuncs &&
6352 !sub->hasSubLinks && !sub->limitCount && !sub->limitOffset &&
6353 !sub->cteList && list_length(sub->rtable) == 1 &&
6354 list_length(sub->targetList) == 1 && sub->jointree &&
6355 list_length(sub->jointree->fromlist) == 1 &&
6356 IsA(linitial(sub->jointree->fromlist), RangeTblRef)) {
6357 RangeTblEntry *qr = (RangeTblEntry *)linitial(sub->rtable);
6358 if (qr->rtekind == RTE_RELATION) {
6361 foreach (lc, qr->eref->colnames) {
6372 if (IsA(node, Query))
6382 if (IsA(node, Query)) {
6383 Query *q = (Query *)node;
6389 foreach (rc, q->cteList) {
6390 CommonTableExpr *cte = (CommonTableExpr *)lfirst(rc);
6430 foreach (rc, q->rtable) {
6431 RangeTblEntry *r = (RangeTblEntry *)lfirst(rc);
6432 if (r->rtekind == RTE_RELATION) {
6434 AttrNumber attid = 1;
6436 foreach (lc, r->eref->colnames) {
6437 const char *v = strVal(lfirst(lc));
6446 }
else if (r->rtekind == RTE_FUNCTION) {
6448 AttrNumber attid = 1;
6450 foreach (lc, r->functions) {
6451 RangeTblFunction *func = (RangeTblFunction *)lfirst(lc);
6453 if (func->funccolcount == 1) {
6454 FuncExpr *expr = (FuncExpr *)func->funcexpr;
6456 !strcmp(get_rte_attribute_name(r, attid),
6462 attid += func->funccolcount;
6464 }
else if (r->rtekind == RTE_SUBQUERY && r->subquery != NULL) {
6514 if (node == NULL || c->
found)
6516 if (IsA(node, SubLink)) {
6517 SubLink *sl = (SubLink *)node;
6518 if (IsA(sl->subselect, Query) &&
6526 if (IsA(node, Query))
6548 if (!c.
found && q->jointree)
6550 if (!c.
found && q->havingQual)
6572 if (IsA(node, SubLink)) {
6574 *out = lappend(*out, node);
6577 if (IsA(node, BoolExpr)) {
6579 foreach (lc, ((BoolExpr *)node)->args)
6583 if (IsA(node, OpExpr)) {
6587 foreach (lc, ((OpExpr *)node)->args) {
6588 Node *a = (Node *)lfirst(lc);
6589 if (IsA(a, RelabelType))
6590 a = (Node *)((RelabelType *)a)->arg;
6591 if (IsA(a, SubLink))
6592 *out = lappend(*out, a);
6618 if (IsA(node, SubLink)) {
6619 SubLink *sl = (SubLink *)node;
6620 if (IsA(sl->subselect, Query) &&
6622 if (list_member_ptr(c->
direct, sl) || sl->subLinkType != EXPR_SUBLINK)
6630 if (IsA(node, Query))
6651 foreach (lc, q->targetList) {
6652 Node *e = (Node *)((TargetEntry *)lfirst(lc))->expr;
6653 if (e && IsA(e, RelabelType))
6654 e = (Node *)((RelabelType *)e)->arg;
6655 if (e && IsA(e, SubLink))
6658 if (q->jointree && q->jointree->quals)
6680 if (IsA(node, FuncExpr) &&
6681 ((FuncExpr *)node)->funcid ==
6682 ((
const constants_t *)data)->OID_FUNCTION_PROVENANCE)
6684 if (IsA(node, Query))
6708 if (IsA(node, Query))
6710 if (IsA(node, SubLink)) {
6711 SubLink *sl = (SubLink *)node;
6712 if (sl->subselect && IsA(sl->subselect, Query) &&
6717 if (sl->subLinkType == EXPR_SUBLINK &&
6719 (Query *)sl->subselect))
6739 ListCell *prev = NULL;
6740 int removed_resno = -1;
6742 foreach (lc, q->targetList) {
6743 TargetEntry *te = (TargetEntry *)lfirst(lc);
6745 removed_resno = te->resno;
6752 if (removed_resno < 0)
6755 foreach (lc, q->targetList) {
6756 TargetEntry *te = (TargetEntry *)lfirst(lc);
6757 if (te->resno > removed_resno)
6773 if (IsA(node, Var)) {
6774 Var *v = (Var *) node;
6793 return expression_tree_walker(node,
aggtoken_walker, (
void*) constants);
6817 if (IsA(node, Var)) {
6818 Var *v = (Var *) node;
6823 if (IsA(node, FuncExpr)) {
6824 FuncExpr *fe = (FuncExpr *) node;
6847 (
void *) constants);
6853 char *name = get_func_name(aggfnoid);
6857 yes = strcmp(name,
"bool_or") == 0 || strcmp(name,
"bool_and") == 0 ||
6858 strcmp(name,
"every") == 0;
6872 if (IsA(n, BoolExpr)) {
6873 BoolExpr *be = (BoolExpr *) n;
6875 foreach (lc, be->args)
6879 if (IsA(n, Aggref)) {
6880 Aggref *ar = (Aggref *) n;
6882 OpExpr *eq = makeNode(OpExpr);
6883 eq->opno = BooleanEqualOperator;
6884 eq->opfuncid = get_opcode(BooleanEqualOperator);
6885 eq->opresulttype = BOOLOID;
6886 eq->opretset =
false;
6887 eq->opcollid = InvalidOid;
6888 eq->inputcollid = InvalidOid;
6889 eq->args = list_make2(ar, makeBoolConst(
true,
false));
6917 SetOperationStmt *setOps = (SetOperationStmt *)q->setOperations;
6918 RangeTblEntry *rte = makeNode(RangeTblEntry);
6919 FromExpr *fe = makeNode(FromExpr);
6920 JoinExpr *je = makeNode(JoinExpr);
6921 BoolExpr *expr = makeNode(BoolExpr);
6925 if (!IsA(setOps->larg, RangeTblRef) || !IsA(setOps->rarg, RangeTblRef)) {
6929 expr->boolop = AND_EXPR;
6930 expr->location = -1;
6933 foreach (lc, q->targetList) {
6934 TargetEntry *te = (TargetEntry *)lfirst(lc);
6937 if (!IsA(te->expr, Var))
6940 v = (Var *)te->expr;
6943 OpExpr *oe = makeNode(OpExpr);
6945 Operator opInfo = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
6946 Form_pg_operator opform;
6947 Var *leftArg, *rightArg;
6949 if (!HeapTupleIsValid(opInfo))
6950 provsql_error(
"could not find operator with OID %u to compare variables of type %u",
6953 opform = (Form_pg_operator)GETSTRUCT(opInfo);
6954 leftArg = makeNode(Var);
6955 rightArg = makeNode(Var);
6958 oe->opfuncid = opform->oprcode;
6959 oe->opresulttype = opform->oprresult;
6960 oe->opcollid = InvalidOid;
6961 oe->inputcollid = DEFAULT_COLLATION_OID;
6963 leftArg->varno = ((RangeTblRef *)setOps->larg)->rtindex;
6964 rightArg->varno = ((RangeTblRef *)setOps->rarg)->rtindex;
6965 leftArg->varattno = rightArg->varattno = attno;
6967#if PG_VERSION_NUM >= 130000
6968 leftArg->varnosyn = rightArg->varnosyn = 0;
6969 leftArg->varattnosyn = rightArg->varattnosyn = 0;
6971 leftArg->varnoold = leftArg->varno;
6972 rightArg->varnoold = rightArg->varno;
6973 leftArg->varoattno = rightArg->varoattno = attno;
6976 leftArg->vartype = rightArg->vartype = v->vartype;
6977 leftArg->varcollid = rightArg->varcollid = InvalidOid;
6978 leftArg->vartypmod = rightArg->vartypmod = -1;
6979 leftArg->location = rightArg->location = -1;
6981 oe->args = list_make2(leftArg, rightArg);
6983 expr->args = lappend(expr->args, oe);
6985 ReleaseSysCache(opInfo);
6999 RangeTblRef *larg_ref = (RangeTblRef *)setOps->larg;
7000 RangeTblRef *rarg_ref = (RangeTblRef *)setOps->rarg;
7001 RangeTblEntry *larg_rte =
7002 (RangeTblEntry *)list_nth(q->rtable, larg_ref->rtindex - 1);
7003 RangeTblEntry *rarg_rte =
7004 (RangeTblEntry *)list_nth(q->rtable, rarg_ref->rtindex - 1);
7005 List *aliasvars = NIL;
7006 List *leftcols = NIL;
7007 List *rightcols = NIL;
7008 List *colnames = NIL;
7013 foreach (lc_te, larg_rte->subquery->targetList) {
7014 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
7019 aliasvars = lappend(aliasvars,
7020 makeVar(larg_ref->rtindex, colno,
7021 exprType((Node *)te->expr),
7022 exprTypmod((Node *)te->expr),
7023 exprCollation((Node *)te->expr),
7025 leftcols = lappend_int(leftcols, colno);
7026 rightcols = lappend_int(rightcols, 0);
7027 colnames = lappend(colnames,
7028 makeString(pstrdup(te->resname ? te->resname
7033 foreach (lc_te, rarg_rte->subquery->targetList) {
7034 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
7039 aliasvars = lappend(aliasvars,
7040 makeVar(rarg_ref->rtindex, colno,
7041 exprType((Node *)te->expr),
7042 exprTypmod((Node *)te->expr),
7043 exprCollation((Node *)te->expr),
7045 leftcols = lappend_int(leftcols, 0);
7046 rightcols = lappend_int(rightcols, colno);
7047 colnames = lappend(colnames,
7048 makeString(pstrdup(te->resname ? te->resname
7054 rte->eref = makeAlias(
"unnamed_join", colnames);
7055 rte->joinaliasvars = aliasvars;
7056#if PG_VERSION_NUM >= 130000
7057 rte->joinleftcols = leftcols;
7058 rte->joinrightcols = rightcols;
7059 rte->joinmergedcols = 0;
7066 rte->rtekind = RTE_JOIN;
7067 rte->jointype = JOIN_LEFT;
7069 q->rtable = lappend(q->rtable, rte);
7071 je->jointype = JOIN_LEFT;
7073 je->larg = setOps->larg;
7074 je->rarg = setOps->rarg;
7075 je->quals = (Node *)expr;
7076 je->rtindex = list_length(q->rtable);
7078 fe->fromlist = list_make1(je);
7084 q->setOperations = 0;
7131 foreach (lc, rel->eref->colnames) {
7133 lfirst(lc) = makeString(pstrdup(
"_provsql_inner"));
7157 if (rel->rtekind == RTE_SUBQUERY) {
7158 int cap = list_length(rel->subquery->targetList);
7159 out->
attno = (AttrNumber *)palloc(cap *
sizeof(AttrNumber));
7160 out->
type = (Oid *)palloc(cap *
sizeof(Oid));
7161 out->
typmod = (int32 *)palloc(cap *
sizeof(int32));
7162 out->
coll = (Oid *)palloc(cap *
sizeof(Oid));
7163 out->
name = (
char **)palloc(cap *
sizeof(
char *));
7165 foreach (lc, rel->subquery->targetList) {
7166 TargetEntry *te = (TargetEntry *)lfirst(lc);
7171 out->
attno[out->
n] = te->resno;
7172 out->
type[out->
n] = exprType((Node *)te->expr);
7173 out->
typmod[out->
n] = exprTypmod((Node *)te->expr);
7174 out->
coll[out->
n] = exprCollation((Node *)te->expr);
7175 out->
name[out->
n] = pstrdup(te->resname ? te->resname :
"?column?");
7182 AttrNumber attid = 0;
7183 int cap = list_length(rel->eref->colnames);
7184 out->
attno = (AttrNumber *)palloc(cap *
sizeof(AttrNumber));
7185 out->
type = (Oid *)palloc(cap *
sizeof(Oid));
7186 out->
typmod = (int32 *)palloc(cap *
sizeof(int32));
7187 out->
coll = (Oid *)palloc(cap *
sizeof(Oid));
7188 out->
name = (
char **)palloc(cap *
sizeof(
char *));
7190 foreach (lc, rel->eref->colnames) {
7191 const char *v = strVal(lfirst(lc));
7200 get_atttypetypmodcoll(rel->relid, attid, &t, &tm, &c);
7201 out->
attno[out->
n] = attid;
7202 out->
type[out->
n] = t;
7204 out->
coll[out->
n] = c;
7205 out->
name[out->
n] = pstrdup(v);
7214 RangeTblEntry *rel) {
7216 AttrNumber attid = 0;
7218 if (rel->rtekind == RTE_SUBQUERY) {
7219 if (rel->subquery == NULL)
7226 foreach (lc, rel->subquery->targetList) {
7227 TargetEntry *te = (TargetEntry *)lfirst(lc);
7228 if (!te->resjunk && te->resname &&
7236 foreach (lc, rel->eref->colnames) {
7248 RangeTblEntry *rte = makeNode(RangeTblEntry);
7249 List *colnames = NIL;
7252 foreach (lc, sub->targetList) {
7253 TargetEntry *te = (TargetEntry *)lfirst(lc);
7256 colnames = lappend(colnames,
7257 makeString(pstrdup(te->resname ? te->resname
7261 rte->rtekind = RTE_SUBQUERY;
7262 rte->subquery = sub;
7264 rte->eref = makeAlias(
"unnamed_subquery", colnames);
7265 rte->lateral =
false;
7266 rte->inFromCl =
true;
7267#if PG_VERSION_NUM < 160000
7268 rte->requiredPerms = 0;
7277 RangeTblEntry *orig) {
7278 RangeTblEntry *c = copyObject(orig);
7279#if PG_VERSION_NUM >= 160000
7280 if (orig->rtekind == RTE_RELATION && orig->perminfoindex != 0) {
7281 RTEPermissionInfo *pi = getRTEPermissionInfo(outer->rteperminfos, orig);
7282 sub->rteperminfos = lappend(sub->rteperminfos, copyObject(pi));
7283 c->perminfoindex = list_length(sub->rteperminfos);
7285 c->perminfoindex = 0;
7299 if (rel->rtekind == RTE_SUBQUERY) {
7300#if PG_VERSION_NUM >= 120000
7301 rel->rtekind = RTE_RESULT;
7302 rel->subquery = NULL;
7307 Query *empty = makeNode(Query);
7308 empty->commandType = CMD_SELECT;
7309 empty->canSetTag =
true;
7310 empty->jointree = makeFromExpr(NIL, NULL);
7311 rel->subquery = empty;
7313 rel->eref = makeAlias(
"*RESULT*", NIL);
7314#if PG_VERSION_NUM >= 160000
7315 rel->perminfoindex = 0;
7333 if (IsA(node, Var)) {
7334 Var *v = (Var *)node;
7335 if (v->varlevelsup == 0) {
7337 for (i = 0; i < c->
npairs; ++i)
7338 if (v->varno == c->
from[i]) {
7339 v = (Var *)copyObject(v);
7340 v->varno = c->
to[i];
7341#if PG_VERSION_NUM >= 160000
7342 v->varnullingrels = NULL;
7344#if PG_VERSION_NUM >= 130000
7353 return expression_tree_mutator(node,
oj_renum_mut, cx);
7364 RangeTblEntry *R, RangeTblEntry *S,
7365 Index R_idx, Index S_idx,
oj_cols *Rc,
7366 oj_cols *Sc, Node *theta,
bool select_r,
7368 Query *sub = makeNode(Query);
7369 RangeTblEntry *Rcopy, *Scopy, *jrte = makeNode(RangeTblEntry);
7370 JoinExpr *je = makeNode(JoinExpr);
7371 RangeTblRef *lr = makeNode(RangeTblRef), *rr = makeNode(RangeTblRef);
7372 FromExpr *fe = makeNode(FromExpr);
7373 List *tl = NIL, *av = NIL, *lcols = NIL, *rcols = NIL, *cn = NIL;
7378 sub->commandType = CMD_SELECT;
7379 sub->canSetTag =
true;
7385 for (i = 0; i < Rc->
n; ++i) {
7388 lcols = lappend_int(lcols, Rc->
attno[i]);
7389 rcols = lappend_int(rcols, 0);
7390 cn = lappend(cn, makeString(pstrdup(Rc->
name[i])));
7392 for (i = 0; i < Sc->
n; ++i) {
7395 lcols = lappend_int(lcols, 0);
7396 rcols = lappend_int(rcols, Sc->
attno[i]);
7397 cn = lappend(cn, makeString(pstrdup(Sc->
name[i])));
7399 jrte->rtekind = RTE_JOIN;
7400 jrte->jointype = JOIN_INNER;
7402 jrte->eref = makeAlias(
"unnamed_join", cn);
7403 jrte->joinaliasvars = av;
7404#if PG_VERSION_NUM >= 130000
7405 jrte->joinleftcols = lcols;
7406 jrte->joinrightcols = rcols;
7407 jrte->joinmergedcols = 0;
7409 jrte->inFromCl =
true;
7411 sub->rtable = list_make3(Rcopy, Scopy, jrte);
7414 rctx.
from[0] = R_idx; rctx.
to[0] = 1;
7415 rctx.
from[1] = S_idx; rctx.
to[1] = 2;
7420 je->jointype = JOIN_INNER;
7421 je->larg = (Node *)lr;
7422 je->rarg = (Node *)rr;
7424 je->isNatural =
false;
7425 je->usingClause = NIL;
7427 fe->fromlist = list_make1(je);
7431 for (i = 0; i < Rc->
n; ++i) {
7434 tl = lappend(tl, makeTargetEntry((Expr *)v, list_length(tl) + 1,
7435 pstrdup(Rc->
name[i]),
false));
7438 for (i = 0; i < Sc->
n; ++i) {
7441 tl = lappend(tl, makeTargetEntry((Expr *)v, list_length(tl) + 1,
7442 pstrdup(Sc->
name[i]),
false));
7444 sub->targetList = tl;
7451 RangeTblEntry *R,
oj_cols *Rc) {
7452 Query *sub = makeNode(Query);
7453 RangeTblEntry *Rcopy;
7454 RangeTblRef *rtr = makeNode(RangeTblRef);
7455 FromExpr *fe = makeNode(FromExpr);
7459 sub->commandType = CMD_SELECT;
7460 sub->canSetTag =
true;
7462 sub->rtable = list_make1(Rcopy);
7464 fe->fromlist = list_make1(rtr);
7467 for (i = 0; i < Rc->
n; ++i) {
7470 tl = lappend(tl, makeTargetEntry((Expr *)v, i + 1, pstrdup(Rc->
name[i]),
7473 sub->targetList = tl;
7485 RangeTblEntry *R, RangeTblEntry *S, Index R_idx,
7488 RangeTblEntry *kept_rel = keep_left ? R : S;
7489 oj_cols *Kc = keep_left ? Rc : Sc;
7493 theta, keep_left, !keep_left);
7496 Query *D = makeNode(Query);
7497 SetOperationStmt *so = makeNode(SetOperationStmt);
7498 RangeTblRef *l = makeNode(RangeTblRef), *r = makeNode(RangeTblRef);
7499 FromExpr *fe = makeNode(FromExpr);
7503 D->commandType = CMD_SELECT;
7504 D->canSetTag =
true;
7505 D->rtable = list_make2(ls_rte, mp_rte);
7509 so->op = SETOP_EXCEPT;
7515 so->larg = (Node *)l;
7516 so->rarg = (Node *)r;
7517 for (i = 0; i < Kc->
n; ++i) {
7518 so->colTypes = lappend_oid(so->colTypes, Kc->
type[i]);
7519 so->colTypmods = lappend_int(so->colTypmods, Kc->
typmod[i]);
7520 so->colCollations = lappend_oid(so->colCollations, Kc->
coll[i]);
7522 D->setOperations = (Node *)so;
7526 for (i = 0; i < Kc->
n; ++i) {
7527 Var *v = makeVar(1, i + 1, Kc->
type[i], Kc->
typmod[i], Kc->
coll[i], 0);
7528 tl = lappend(tl, makeTargetEntry((Expr *)v, i + 1, pstrdup(Kc->
name[i]),
7544 RangeTblEntry *R, RangeTblEntry *S,
7545 Index R_idx, Index S_idx,
oj_cols *Rc,
7546 oj_cols *Sc, Node *theta,
bool keep_left) {
7547 Query *D =
oj_build_diff(constants, outer, R, S, R_idx, S_idx, Rc, Sc, theta,
7550 Query *A = makeNode(Query);
7551 RangeTblRef *rtr = makeNode(RangeTblRef);
7552 FromExpr *fe = makeNode(FromExpr);
7556 A->commandType = CMD_SELECT;
7557 A->canSetTag =
true;
7558 A->rtable = list_make1(D_rte);
7560 fe->fromlist = list_make1(rtr);
7564 for (i = 0; i < Rc->
n; ++i) {
7567 e = (Expr *)makeVar(1, ++kept, Rc->
type[i], Rc->
typmod[i], Rc->
coll[i],
7570 e = (Expr *)makeNullConst(Rc->
type[i], Rc->
typmod[i], Rc->
coll[i]);
7571 tl = lappend(tl, makeTargetEntry(e, list_length(tl) + 1,
7572 pstrdup(Rc->
name[i]),
false));
7575 for (i = 0; i < Sc->
n; ++i) {
7578 e = (Expr *)makeNullConst(Sc->
type[i], Sc->
typmod[i], Sc->
coll[i]);
7580 e = (Expr *)makeVar(1, ++kept, Sc->
type[i], Sc->
typmod[i], Sc->
coll[i],
7582 tl = lappend(tl, makeTargetEntry(e, list_length(tl) + 1,
7583 pstrdup(Sc->
name[i]),
false));
7592 List **typmods, List **collations) {
7594 *types = *typmods = *collations = NIL;
7595 for (i = 0; i < Rc->
n; ++i) {
7596 *types = lappend_oid(*types, Rc->
type[i]);
7597 *typmods = lappend_int(*typmods, Rc->
typmod[i]);
7598 *collations = lappend_oid(*collations, Rc->
coll[i]);
7600 for (i = 0; i < Sc->
n; ++i) {
7601 *types = lappend_oid(*types, Sc->
type[i]);
7602 *typmods = lappend_int(*typmods, Sc->
typmod[i]);
7603 *collations = lappend_oid(*collations, Sc->
coll[i]);
7615 RangeTblEntry *R, RangeTblEntry *S, Index R_idx,
7617 JoinType jointype) {
7619 List *types, *typmods, *collations;
7620 Query *Q = makeNode(Query);
7621 FromExpr *fe = makeNode(FromExpr);
7629 S_idx, Rc, Sc, theta,
true,
true));
7630 if (jointype == JOIN_LEFT || jointype == JOIN_FULL)
7632 S_idx, Rc, Sc, theta,
true));
7633 if (jointype == JOIN_RIGHT || jointype == JOIN_FULL)
7635 S_idx, Rc, Sc, theta,
false));
7637 Q->commandType = CMD_SELECT;
7638 Q->canSetTag =
true;
7648 RangeTblRef *first = makeNode(RangeTblRef);
7650 tree = (Node *)first;
7652 for (k = 2; k <= list_length(arms); ++k) {
7653 SetOperationStmt *so = makeNode(SetOperationStmt);
7654 RangeTblRef *rtr = makeNode(RangeTblRef);
7656 so->op = SETOP_UNION;
7659 so->rarg = (Node *)rtr;
7660 so->colTypes = list_copy(types);
7661 so->colTypmods = list_copy(typmods);
7662 so->colCollations = list_copy(collations);
7665 Q->setOperations = tree;
7670 for (i = 0; i < Rc->
n; ++i) {
7671 Var *v = makeVar(1, ++pos, Rc->
type[i], Rc->
typmod[i], Rc->
coll[i], 0);
7672 tl = lappend(tl, makeTargetEntry((Expr *)v, pos, pstrdup(Rc->
name[i]),
7675 for (i = 0; i < Sc->
n; ++i) {
7676 Var *v = makeVar(1, ++pos, Sc->
type[i], Sc->
typmod[i], Sc->
coll[i], 0);
7677 tl = lappend(tl, makeTargetEntry((Expr *)v, pos, pstrdup(Sc->
name[i]),
7693 if (IsA(node, Var)) {
7694 Var *v = (Var *)node;
7695 return (v->varlevelsup == 0 && v->varno == c->
join_idx);
7708 if (q->jointree && q->jointree->quals &&
7728 if (IsA(node, Var)) {
7729 Var *v = (Var *)node;
7730 if (v->varlevelsup == 0 &&
7731 (v->varno == c->
R_idx || v->varno == c->
S_idx)) {
7732 v = (Var *)copyObject(v);
7733 if ((Index)((Var *)node)->varno == c->
R_idx)
7734 v->varattno = c->
R_map[v->varattno];
7736 v->varattno = c->
S_map[v->varattno];
7738#if PG_VERSION_NUM >= 160000
7739 v->varnullingrels = NULL;
7741#if PG_VERSION_NUM >= 130000
7764 RangeTblRef *lref, *rref;
7765 Index R_idx, S_idx, join_idx;
7766 RangeTblEntry *R_rte, *S_rte;
7770 AttrNumber *R_map, *S_map;
7771 int ncolR, ncolS, i;
7774 if (q->commandType != CMD_SELECT)
7776 if (!q->jointree || list_length(q->jointree->fromlist) != 1)
7778 if (!IsA(linitial(q->jointree->fromlist), JoinExpr))
7780 je = (JoinExpr *)linitial(q->jointree->fromlist);
7781 if (je->jointype != JOIN_LEFT && je->jointype != JOIN_RIGHT &&
7782 je->jointype != JOIN_FULL)
7784 if (!IsA(je->larg, RangeTblRef) || !IsA(je->rarg, RangeTblRef))
7787 lref = (RangeTblRef *)je->larg;
7788 rref = (RangeTblRef *)je->rarg;
7789 R_idx = lref->rtindex;
7790 S_idx = rref->rtindex;
7791 join_idx = je->rtindex;
7792 R_rte = list_nth_node(RangeTblEntry, q->rtable, R_idx - 1);
7793 S_rte = list_nth_node(RangeTblEntry, q->rtable, S_idx - 1);
7795 if ((R_rte->rtekind != RTE_RELATION && R_rte->rtekind != RTE_SUBQUERY) ||
7796 (S_rte->rtekind != RTE_RELATION && S_rte->rtekind != RTE_SUBQUERY))
7798 if ((R_rte->rtekind == RTE_SUBQUERY && R_rte->lateral) ||
7799 (S_rte->rtekind == RTE_SUBQUERY && S_rte->lateral))
7807#if PG_VERSION_NUM >= 180000
7816 ncolR = (R_rte->rtekind == RTE_SUBQUERY)
7817 ? list_length(R_rte->subquery->targetList)
7818 : list_length(R_rte->eref->colnames);
7819 ncolS = (S_rte->rtekind == RTE_SUBQUERY)
7820 ? list_length(S_rte->subquery->targetList)
7821 : list_length(S_rte->eref->colnames);
7823 Q =
oj_build_union(constants, q, R_rte, S_rte, R_idx, S_idx, &Rc, &Sc, theta,
7832 R_map = (AttrNumber *)palloc0((ncolR + 1) *
sizeof(AttrNumber));
7833 S_map = (AttrNumber *)palloc0((ncolS + 1) *
sizeof(AttrNumber));
7834 for (i = 0; i < Rc.
n; ++i)
7835 R_map[Rc.
attno[i]] = i + 1;
7836 for (i = 0; i < Sc.
n; ++i)
7837 S_map[Sc.
attno[i]] = Rc.
n + i + 1;
7846 RangeTblEntry *J_rte =
7847 list_nth_node(RangeTblEntry, q->rtable, join_idx - 1);
7850 J_rte->rtekind = RTE_SUBQUERY;
7851 J_rte->subquery = Q;
7852 J_rte->jointype = JOIN_INNER;
7853 J_rte->joinaliasvars = NIL;
7854#if PG_VERSION_NUM >= 130000
7855 J_rte->joinleftcols = NIL;
7856 J_rte->joinrightcols = NIL;
7857 J_rte->joinmergedcols = 0;
7859 J_rte->relid = InvalidOid;
7861#if PG_VERSION_NUM >= 120000
7862 J_rte->rellockmode = 0;
7865 J_rte->lateral =
false;
7866 J_rte->tablesample = NULL;
7867#if PG_VERSION_NUM >= 160000
7868 J_rte->perminfoindex = 0;
7870 J_rte->selectedCols = NULL;
7871 J_rte->insertedCols = NULL;
7872 J_rte->updatedCols = NULL;
7873 J_rte->requiredPerms = ACL_SELECT;
7875 for (i = 0; i < Rc.
n; ++i)
7876 cn = lappend(cn, makeString(pstrdup(Rc.
name[i])));
7877 for (i = 0; i < Sc.
n; ++i)
7878 cn = lappend(cn, makeString(pstrdup(Sc.
name[i])));
7879 J_rte->eref = makeAlias(
"unnamed_subquery", cn);
7883 RangeTblRef *newr = makeNode(RangeTblRef);
7884 newr->rtindex = join_idx;
7885 q->jointree->fromlist = list_make1(newr);
7893 q->targetList = (List *)
oj_outer_remap((Node *)q->targetList, &octx);
7894 if (q->jointree->quals)
7933 if (IsA(node, Var)) {
7934 Var *v = (Var *)node;
7935 if (v->varlevelsup == 1) {
7936 v = (Var *)copyObject(v);
7940 if (v->varlevelsup == 0 && v->varno == c->
q_old) {
7941 v = (Var *)copyObject(v);
7942 v->varno = c->
q_new;
7943#if PG_VERSION_NUM >= 130000
7973 if (IsA(node, Var)) {
7974 Var *v = (Var *)node;
7975 if (s->
found_var == NULL && v->varlevelsup == 0 &&
7993 if (node == (Node *)c->
target)
8002 if (node == (Node *)cx)
8010 Aggref *agg = makeNode(Aggref);
8011 TargetEntry *te = makeNode(TargetEntry);
8014 agg->aggfnoid = aggfnoid;
8015 agg->aggtype = aggtype;
8016 agg->aggtranstype = InvalidOid;
8017 agg->aggargtypes = list_make1_oid(argtype);
8018 agg->args = list_make1(te);
8019 agg->aggkind = AGGKIND_NORMAL;
8020 agg->aggsplit = AGGSPLIT_SIMPLE;
8022#if PG_VERSION_NUM >= 140000
8023 agg->aggno = agg->aggtransno = -1;
8038 Var *qkey = (Var *)copyObject((Node *)found_var);
8040 OpExpr *op = makeNode(OpExpr);
8043 qkey->varno = q_idx;
8044#if PG_VERSION_NUM >= 130000
8046 qkey->varattnosyn = 0;
8050 o = OpernameGetOprid(list_make1(makeString((
char *)opstr)), INT8OID, INT8OID);
8052 op->opfuncid = get_opcode(o);
8053 op->opresulttype = BOOLOID;
8054 op->opcollid = InvalidOid;
8055 op->inputcollid = InvalidOid;
8056 op->args = list_make2(cnt, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
8057 Int64GetDatum(n),
false, FLOAT8PASSBYVAL));
8067 Aggref *cnt = makeNode(Aggref);
8068 TargetEntry *arg = makeTargetEntry((Expr *)copyObject((Node *)valexpr), 1,
8070 SortGroupClause *sgc = makeNode(SortGroupClause);
8071 OpExpr *op = makeNode(OpExpr);
8074 arg->ressortgroupref = 1;
8075 sgc->tleSortGroupRef = 1;
8076 get_sort_group_operators(exprType((Node *)valexpr),
false,
true,
false,
8077 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
8080 cnt->aggtype = INT8OID;
8081 cnt->aggtranstype = InvalidOid;
8082 cnt->aggargtypes = list_make1_oid(exprType((Node *)valexpr));
8083 cnt->args = list_make1(arg);
8084 cnt->aggdistinct = list_make1(sgc);
8085 cnt->aggkind = AGGKIND_NORMAL;
8086 cnt->aggsplit = AGGSPLIT_SIMPLE;
8088#if PG_VERSION_NUM >= 140000
8089 cnt->aggno = cnt->aggtransno = -1;
8092 o = OpernameGetOprid(list_make1(makeString((
char *)opstr)), INT8OID, INT8OID);
8094 op->opfuncid = get_opcode(o);
8095 op->opresulttype = BOOLOID;
8096 op->opcollid = InvalidOid;
8097 op->inputcollid = InvalidOid;
8098 op->args = list_make2(cnt, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
8099 Int64GetDatum(n),
false, FLOAT8PASSBYVAL));
8120 if (c->
skip && node == (Node *)c->
skip)
8122 if (IsA(node, Var)) {
8123 Var *v = (Var *)node;
8124 if ((
int)v->varlevelsup == c->
target_level && (
int)v->varno >= 1 &&
8125 (
int)v->varno <= c->
rtlen && c->
pos[v->varno] != NULL &&
8126 v->varattno >= 1 && c->
pos[v->varno][v->varattno] > 0) {
8127 Var *nv = (Var *)copyObject(v);
8129 nv->varattno = c->
pos[v->varno][v->varattno];
8130#if PG_VERSION_NUM >= 130000
8132 nv->varattnosyn = 0;
8154 SubLink *sl,
bool in_where) {
8155 int rtlen = list_length(q->rtable);
8156 int **pos = (
int **)palloc0((rtlen + 1) *
sizeof(
int *));
8157 Query *Rp = makeNode(Query);
8158 RangeTblEntry *rp_rte;
8159 RangeTblRef *rtr = makeNode(RangeTblRef);
8160 FromExpr *outer_fe = makeNode(FromExpr);
8162 Node *subquery_conj = NULL;
8163 List *kept_conj = NIL;
8167 bool any_tracked =
false;
8171 foreach (lc, q->rtable) {
8172 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8174 if (r->rtekind == RTE_RELATION) {
8177 }
else if (r->rtekind != RTE_JOIN) {
8184 foreach (lc, q->rtable) {
8185 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8189 if (r->rtekind != RTE_RELATION)
8192 pos[idx] = (
int *)palloc0((list_length(r->eref->colnames) + 1) *
sizeof(
int));
8193 for (j = 0; j < rc.
n; ++j) {
8195 rp_tl = lappend(rp_tl, makeTargetEntry((Expr *)v, ++posn,
8196 pstrdup(rc.
name[j]),
false));
8197 pos[idx][rc.
attno[j]] = posn;
8207 FuncExpr *one = makeNode(FuncExpr);
8212 rp_tl = lappend(rp_tl, makeTargetEntry((Expr *)one, ++posn,
8218 if (q->jointree->quals) {
8219 Node *quals = q->jointree->quals;
8220 List *conjs = (IsA(quals, BoolExpr) &&
8221 ((BoolExpr *)quals)->boolop == AND_EXPR)
8222 ? ((BoolExpr *)quals)->args
8223 : list_make1(quals);
8224 foreach (lc, conjs) {
8225 Node *cnode = (Node *)lfirst(lc);
8227 subquery_conj = cnode;
8229 kept_conj = lappend(kept_conj, cnode);
8234 Rp->commandType = CMD_SELECT;
8235 Rp->canSetTag =
true;
8236 Rp->rtable = q->rtable;
8237 Rp->jointree = makeNode(FromExpr);
8238 Rp->jointree->fromlist = q->jointree->fromlist;
8239 Rp->jointree->quals =
8242 : (list_length(kept_conj) == 1 ? (Node *)linitial(kept_conj)
8243 : (Node *)makeBoolExpr(AND_EXPR, kept_conj,
8245 Rp->targetList = rp_tl;
8246#if PG_VERSION_NUM >= 160000
8247 Rp->rteperminfos = q->rteperminfos;
8267 Query *sub = (Query *)sl->subselect;
8271 if (sub->jointree && sub->jointree->quals)
8277 q->rtable = list_make1(rp_rte);
8278#if PG_VERSION_NUM >= 160000
8279 q->rteperminfos = NIL;
8282 outer_fe->fromlist = list_make1(rtr);
8283 outer_fe->quals = subquery_conj;
8284 q->jointree = outer_fe;
8303 bool corr_supplied) {
8305 if (!IsA(sub, Query) || sub->commandType != CMD_SELECT)
8307 if (sub->groupClause || sub->groupingSets || sub->hasAggs ||
8308 sub->distinctClause || sub->setOperations || sub->hasWindowFuncs ||
8309 sub->hasSubLinks || sub->limitCount || sub->limitOffset || sub->cteList ||
8312 if (!sub->jointree || (!corr_supplied && !sub->jointree->quals))
8317 foreach (lc, sub->rtable) {
8318 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8322 foreach (lc, sub->jointree->fromlist) {
8323 if (!IsA(lfirst(lc), RangeTblRef))
8348 Query *sq = (Query *)copyObject(subselect);
8349 Aggref *cnt = makeNode(Aggref);
8350 SubLink *sl = makeNode(SubLink);
8351 OpExpr *op = makeNode(OpExpr);
8355 sq->jointree->quals =
8357 ? (Node *)makeBoolExpr(AND_EXPR,
8358 list_make2(sq->jointree->quals, extra_corr), -1)
8362 cnt->aggtype = INT8OID;
8363 cnt->aggtranstype = InvalidOid;
8364 cnt->aggargtypes = NIL;
8366 cnt->aggstar =
true;
8367 cnt->aggkind = AGGKIND_NORMAL;
8368 cnt->aggsplit = AGGSPLIT_SIMPLE;
8370#if PG_VERSION_NUM >= 140000
8371 cnt->aggno = cnt->aggtransno = -1;
8374 list_make1(makeTargetEntry((Expr *)cnt, 1, pstrdup(
"count"),
false));
8377 sl->subLinkType = EXPR_SUBLINK;
8378 sl->subselect = (Node *)sq;
8379 sl->testexpr = NULL;
8383 o = OpernameGetOprid(list_make1(makeString(antijoin ?
"=" :
">=")), INT8OID,
8386 op->opfuncid = get_opcode(o);
8387 op->opresulttype = BOOLOID;
8388 op->opcollid = InvalidOid;
8389 op->inputcollid = InvalidOid;
8390 op->args = list_make2(sl, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
8391 Int64GetDatum(antijoin ? 0 : 1),
false,
8408 if (IsA(node, Param)) {
8409 Param *p = (Param *)node;
8410 if (p->paramkind == PARAM_SUBLINK && p->paramid == c->
paramid)
8423 foreach (lc, body->rtable) {
8424 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8425 if ((r->rtekind == RTE_RELATION || r->rtekind == RTE_SUBQUERY) &&
8451 List *conjs, *newconjs = NIL;
8453 bool changed =
false;
8455 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
8456 !q->jointree->quals)
8459 quals = q->jointree->quals;
8460 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
8461 ? ((BoolExpr *)quals)->args
8462 : list_make1(quals);
8464 foreach (lc, conjs) {
8465 Node *c = (Node *)lfirst(lc);
8466 Node *inner = c, *rewritten = NULL;
8469 if (IsA(c, BoolExpr) && ((BoolExpr *)c)->boolop == NOT_EXPR &&
8470 list_length(((BoolExpr *)c)->args) == 1) {
8472 inner = (Node *)linitial(((BoolExpr *)c)->args);
8474 if (IsA(inner, SubLink) &&
8475 (((SubLink *)inner)->subLinkType == ANY_SUBLINK ||
8476 ((SubLink *)inner)->subLinkType == ALL_SUBLINK) &&
8477 IsA(((SubLink *)inner)->subselect, Query)) {
8478 SubLink *sl = (SubLink *)inner;
8479 Query *body = (Query *)sl->subselect;
8480 if (body->commandType == CMD_SELECT && body->hasAggs &&
8481 !body->groupClause && !body->groupingSets && !body->setOperations &&
8482 !body->hasWindowFuncs && !body->hasSubLinks && !body->limitCount &&
8483 !body->limitOffset && !body->cteList &&
8484 list_length(body->targetList) == 1 &&
8485 IsA(((TargetEntry *)linitial(body->targetList))->expr, Aggref) &&
8486 sl->testexpr && IsA(sl->testexpr, OpExpr) &&
8487 list_length(((OpExpr *)sl->testexpr)->args) == 2 &&
8489 OpExpr *op = (OpExpr *)copyObject(sl->testexpr);
8490 Oid opno = neg ? get_negator(op->opno) : op->opno;
8491 if (OidIsValid(opno)) {
8492 SubLink *esl = makeNode(SubLink);
8494 esl->subLinkType = EXPR_SUBLINK;
8495 esl->testexpr = NULL;
8496 esl->operName = NIL;
8497 esl->subselect = (Node *)copyObject(body);
8500 op->opfuncid = get_opcode(opno);
8507 newconjs = lappend(newconjs, rewritten ? rewritten : c);
8513 q->jointree->quals = (list_length(newconjs) == 1)
8514 ? (Node *)linitial(newconjs)
8515 : (Node *)makeBoolExpr(AND_EXPR, newconjs, -1);
8534 Query *sub = (Query *)sl->subselect;
8535 List *opexprs, *conjs = NIL;
8542 if (sl->subLinkType == ANY_SUBLINK) {
8545 }
else if (sl->subLinkType == ALL_SUBLINK) {
8554 if (IsA(sl->testexpr, OpExpr))
8555 opexprs = list_make1(sl->testexpr);
8556 else if (sl->subLinkType == ANY_SUBLINK && IsA(sl->testexpr, BoolExpr) &&
8557 ((BoolExpr *)sl->testexpr)->boolop == AND_EXPR)
8558 opexprs = ((BoolExpr *)sl->testexpr)->args;
8562 foreach (lc, opexprs) {
8563 OpExpr *oe = (OpExpr *)lfirst(lc);
8564 Node *rhs, *qcol, *ci;
8568 if (!IsA(oe, OpExpr) || list_length(oe->args) != 2)
8570 rhs = (Node *)lsecond(oe->args);
8571 if (IsA(rhs, RelabelType))
8572 rhs = (Node *)((RelabelType *)rhs)->arg;
8573 if (!IsA(rhs, Param))
8576 if (p->paramkind != PARAM_SUBLINK || p->paramid < 1 ||
8577 p->paramid > list_length(sub->targetList))
8583 ci = copyObject((Node *)oe);
8585 Oid neg = get_negator(((OpExpr *)ci)->opno);
8586 if (!OidIsValid(neg))
8588 ((OpExpr *)ci)->opno = neg;
8589 ((OpExpr *)ci)->opfuncid = get_opcode(neg);
8591 IncrementVarSublevelsUp(ci, 1, 0);
8593 (Node *)((TargetEntry *)list_nth(sub->targetList, p->paramid - 1))->expr);
8601 return (list_length(conjs) == 1)
8602 ? (Node *)linitial(conjs)
8603 : (Node *)makeBoolExpr(AND_EXPR, conjs, -1);
8620 List *conjs, *newconjs = NIL;
8622 bool changed =
false;
8624 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
8625 !q->jointree->quals)
8628 quals = q->jointree->quals;
8629 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
8630 ? ((BoolExpr *)quals)->args
8631 : list_make1(quals);
8633 foreach (lc, conjs) {
8634 Node *c = (Node *)lfirst(lc);
8635 Node *inner = c, *rewritten = NULL;
8639 if (IsA(c, BoolExpr) && ((BoolExpr *)c)->boolop == NOT_EXPR &&
8640 list_length(((BoolExpr *)c)->args) == 1) {
8642 inner = (Node *)linitial(((BoolExpr *)c)->args);
8644 if (IsA(inner, SubLink) && IsA(((SubLink *)inner)->subselect, Query)) {
8645 sl = (SubLink *)inner;
8646 if (sl->subLinkType == EXISTS_SUBLINK &&
8648 (Query *)sl->subselect,
false)) {
8652 }
else if (sl->subLinkType == ANY_SUBLINK ||
8653 sl->subLinkType == ALL_SUBLINK) {
8660 (Query *)sl->subselect,
true))
8662 base_antijoin ^ neg);
8665 newconjs = lappend(newconjs, rewritten ? rewritten : c);
8671 q->jointree->quals = (list_length(newconjs) == 1)
8672 ? (Node *)linitial(newconjs)
8673 : (Node *)makeBoolExpr(AND_EXPR, newconjs, -1);
8691 bool changed =
false;
8693 if (q->commandType != CMD_SELECT || !q->hasSubLinks)
8696 foreach (lc, q->targetList) {
8697 TargetEntry *te = (TargetEntry *)lfirst(lc);
8700 TargetEntry *innerte;
8701 Oid elemtype, arrtype;
8706 if (!IsA(te->expr, SubLink))
8708 sl = (SubLink *)te->expr;
8709 if (sl->subLinkType != ARRAY_SUBLINK || !IsA(sl->subselect, Query))
8711 sub = (Query *)sl->subselect;
8720 foreach (tlc, sub->targetList)
8721 if (!((TargetEntry *)lfirst(tlc))->resjunk)
8723 if (nreal != 1 || ((TargetEntry *)linitial(sub->targetList))->resjunk)
8727 innerte = (TargetEntry *)linitial(sub->targetList);
8728 elemtype = exprType((Node *)innerte->expr);
8729 arrtype = get_array_type(elemtype);
8730 if (!OidIsValid(arrtype))
8742 if (sub->sortClause) {
8750 List *args = NIL, *argtypes = NIL;
8752 agg = makeNode(Aggref);
8753 foreach (alc, sub->targetList) {
8754 TargetEntry *ate = (TargetEntry *)copyObject(lfirst(alc));
8755 args = lappend(args, ate);
8756 argtypes = lappend_oid(argtypes, exprType((Node *)ate->expr));
8759 agg->aggtype = arrtype;
8760 agg->aggtranstype = InvalidOid;
8761 agg->aggargtypes = argtypes;
8763 agg->aggorder = (List *)copyObject((Node *)sub->sortClause);
8764 agg->aggkind = AGGKIND_NORMAL;
8765 agg->aggsplit = AGGSPLIT_SIMPLE;
8767#if PG_VERSION_NUM >= 140000
8768 agg->aggno = agg->aggtransno = -1;
8779 nt = makeNode(NullTest);
8780 nt->arg = (Expr *)copyObject((Node *)scan.
found_var);
8781 nt->nulltesttype = IS_NOT_NULL;
8782 nt->argisrow =
false;
8784 agg->aggfilter = (Expr *)nt;
8789 sub->targetList = list_make1(makeTargetEntry(
8790 (Expr *)agg, 1, innerte->resname ? pstrdup(innerte->resname) : NULL,
8792 sub->sortClause = NIL;
8793 sub->hasAggs =
true;
8794 sl->subLinkType = EXPR_SUBLINK;
8814 int rtlen = list_length(sub->rtable);
8816 Query *D = makeNode(Query);
8817 RangeTblEntry *d_rte;
8818 RangeTblRef *rtr = makeNode(RangeTblRef);
8824 if (!sub->jointree || sub->jointree->fromlist == NIL)
8826 foreach (lc, sub->rtable) {
8827 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8831 foreach (lc, sub->jointree->fromlist) {
8832 if (!IsA(lfirst(lc), RangeTblRef))
8837 pos = (
int **)palloc0((rtlen + 1) *
sizeof(
int *));
8839 foreach (lc, sub->rtable) {
8840 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8846 (
int *)palloc0((list_length(r->eref->colnames) + 1) *
sizeof(
int));
8847 for (j = 0; j < rc.
n; ++j) {
8850 d_tl = lappend(d_tl, makeTargetEntry((Expr *)v, ++posn,
8851 pstrdup(rc.
name[j]),
false));
8852 pos[idx][rc.
attno[j]] = posn;
8857 D->commandType = CMD_SELECT;
8858 D->canSetTag =
true;
8859 D->rtable = sub->rtable;
8860 D->jointree = makeNode(FromExpr);
8861 D->jointree->fromlist = sub->jointree->fromlist;
8862 D->jointree->quals = NULL;
8863 D->targetList = d_tl;
8864#if PG_VERSION_NUM >= 160000
8865 D->rteperminfos = sub->rteperminfos;
8875 if (sub->jointree->quals)
8880 sub->rtable = list_make1(d_rte);
8881#if PG_VERSION_NUM >= 160000
8882 sub->rteperminfos = NIL;
8885 sub->jointree->fromlist = list_make1(rtr);
8910 if (!IsA(body, Query) || body->commandType != CMD_SELECT)
8912 if (body->groupClause || body->groupingSets || body->distinctClause ||
8913 body->setOperations || body->hasWindowFuncs || body->hasSubLinks ||
8914 body->limitCount || body->limitOffset || body->cteList ||
8915 list_length(body->targetList) != 1)
8917 if (!body->jointree || body->jointree->fromlist == NIL)
8920 if (contain_vars_of_level((Node *)body->targetList, 1) ||
8921 (body->jointree->quals && contain_vars_of_level(body->jointree->quals, 1)))
8925 foreach (lc, body->rtable) {
8926 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
8930 foreach (lc, body->jointree->fromlist) {
8931 if (!IsA(lfirst(lc), RangeTblRef))
8935 vte = (TargetEntry *)linitial(body->targetList);
8937 if (body->hasAggs) {
8939 if (!IsA(vte->expr, Aggref))
8941 D = (Query *)copyObject(body);
8951 D = (Query *)copyObject(body);
8952 vte = (TargetEntry *)linitial(D->targetList);
8954 exprType((Node *)vte->expr),
8955 exprType((Node *)vte->expr), vte->expr);
8958 cnt = makeNode(Aggref);
8960 cnt->aggtype = INT8OID;
8961 cnt->aggtranstype = InvalidOid;
8962 cnt->aggargtypes = NIL;
8964 cnt->aggstar =
true;
8965 cnt->aggkind = AGGKIND_NORMAL;
8966 cnt->aggsplit = AGGSPLIT_SIMPLE;
8968#if PG_VERSION_NUM >= 140000
8969 cnt->aggno = cnt->aggtransno = -1;
8971 le = makeNode(OpExpr);
8972 le_op = OpernameGetOprid(list_make1(makeString(
"<=")), INT8OID, INT8OID);
8974 le->opfuncid = get_opcode(le_op);
8975 le->opresulttype = BOOLOID;
8976 le->opcollid = InvalidOid;
8977 le->inputcollid = InvalidOid;
8978 le->args = list_make2(cnt, makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
8979 Int64GetDatum(1),
false,
8982 D->havingQual = (Node *)le;
8992 if (!IsA(sub, Query) || sub->commandType != CMD_SELECT)
8994 if (sub->groupClause || sub->groupingSets || sub->distinctClause ||
8995 sub->setOperations || sub->hasWindowFuncs || sub->hasSubLinks ||
8996 sub->limitCount || sub->limitOffset || sub->cteList)
8998 if (!sub->jointree || sub->jointree->fromlist == NIL)
9000 if (contain_vars_of_level((Node *)sub->targetList, 1) ||
9001 (sub->jointree->quals && contain_vars_of_level(sub->jointree->quals, 1)))
9003 foreach (lc, sub->rtable) {
9004 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
9008 foreach (lc, sub->jointree->fromlist) {
9009 if (!IsA(lfirst(lc), RangeTblRef))
9017 Aggref *cnt = makeNode(Aggref);
9019 cnt->aggtype = INT8OID;
9020 cnt->aggtranstype = InvalidOid;
9021 cnt->aggargtypes = NIL;
9023 cnt->aggstar =
true;
9024 cnt->aggkind = AGGKIND_NORMAL;
9025 cnt->aggsplit = AGGSPLIT_SIMPLE;
9027#if PG_VERSION_NUM >= 140000
9028 cnt->aggno = cnt->aggtransno = -1;
9037 Query *D = (Query *)copyObject(body);
9038 D->targetList = list_make1(makeTargetEntry(
9039 (Expr *)makeConst(INT4OID, -1, InvalidOid,
sizeof(int32), Int32GetDatum(1),
9041 1, pstrdup(
"exists"),
false));
9042 D->havingQual = pred;
9063 List *conjs, *newconjs = NIL;
9065 bool changed =
false;
9067 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
9068 !q->jointree->quals)
9071 quals = q->jointree->quals;
9072 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
9073 ? ((BoolExpr *)quals)->args
9074 : list_make1(quals);
9076 foreach (lc, conjs) {
9077 Node *c = (Node *)lfirst(lc);
9080 if (IsA(c, SubLink) && ((SubLink *)c)->subLinkType == EXISTS_SUBLINK &&
9081 IsA(((SubLink *)c)->subselect, Query) &&
9083 (Query *)((SubLink *)c)->subselect)) {
9085 OpExpr *ge = makeNode(OpExpr);
9086 Oid o = OpernameGetOprid(list_make1(makeString(
">=")), INT8OID, INT8OID);
9088 ge->opfuncid = get_opcode(o);
9089 ge->opresulttype = BOOLOID;
9090 ge->opcollid = InvalidOid;
9091 ge->inputcollid = InvalidOid;
9093 makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
9094 Int64GetDatum(1),
false, FLOAT8PASSBYVAL));
9098 }
else if (IsA(c, OpExpr) && list_length(((OpExpr *)c)->args) == 2) {
9099 OpExpr *op = (OpExpr *)c;
9100 Node *l = (Node *)linitial(op->args), *r = (Node *)lsecond(op->args);
9103 bool sublink_left =
false;
9105 if (IsA(l, SubLink)) {
9108 sublink_left =
true;
9109 }
else if (IsA(r, SubLink)) {
9113 if (sl != NULL && sl->subLinkType == EXPR_SUBLINK &&
9114 IsA(sl->subselect, Query)) {
9115 Query *sub = (Query *)sl->subselect;
9116 if (sub->hasAggs && list_length(sub->targetList) == 1 &&
9117 IsA(((TargetEntry *)linitial(sub->targetList))->expr, Aggref) &&
9119 !contain_vars_of_level(val, 0)) {
9122 copyObject((Node *)((TargetEntry *)linitial(sub->targetList))->expr);
9123 OpExpr *pred = (OpExpr *)copyObject((Node *)op);
9124 pred->args = sublink_left ? list_make2(agg, copyObject(val))
9125 : list_make2(copyObject(val), agg);
9127 }
else if (!sub->hasAggs && list_length(sub->targetList) == 1 &&
9128 !((TargetEntry *)linitial(sub->targetList))->resjunk &&
9131 !contain_vars_of_level(val, 0)) {
9138 Expr *bodyval = ((TargetEntry *)linitial(sub->targetList))->expr;
9140 exprType((Node *)bodyval),
9141 exprType((Node *)bodyval),
9142 (Expr *)copyObject((Node *)bodyval));
9143 OpExpr *cmp = (OpExpr *)copyObject((Node *)op);
9144 Oid leo = OpernameGetOprid(list_make1(makeString(
"<=")), INT8OID,
9146 OpExpr *le1 = makeNode(OpExpr);
9148 cmp->args = sublink_left ? list_make2(ch, copyObject(val))
9149 : list_make2(copyObject(val), ch);
9151 le1->opfuncid = get_opcode(leo);
9152 le1->opresulttype = BOOLOID;
9153 le1->opcollid = InvalidOid;
9154 le1->inputcollid = InvalidOid;
9157 makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
9158 Int64GetDatum(1),
false, FLOAT8PASSBYVAL));
9161 sub, (Node *)makeBoolExpr(AND_EXPR, list_make2(cmp, le1), -1));
9168 RangeTblRef *rtr = makeNode(RangeTblRef);
9169 q->rtable = lappend(q->rtable, d_rte);
9170 rtr->rtindex = list_length(q->rtable);
9171 q->jointree->fromlist = lappend(q->jointree->fromlist, rtr);
9174 newconjs = lappend(newconjs, c);
9180 q->jointree->quals =
9183 : (list_length(newconjs) == 1 ? (Node *)linitial(newconjs)
9184 : (Node *)makeBoolExpr(AND_EXPR, newconjs,
9191 if (q->jointree->quals)
9194 q->hasSubLinks =
false;
9203 OpExpr *op = makeNode(OpExpr);
9205 op->opfuncid = get_opcode(opno);
9206 op->opresulttype = BOOLOID;
9207 op->opcollid = InvalidOid;
9208 op->inputcollid = inputcollid;
9209 op->args = list_make2(cnt, copyObject(constarg));
9218 return DatumGetBool(OidFunctionCall2Coll(get_opcode(opno), c->constcollid,
9219 Int64GetDatum(0), c->constvalue));
9246 List *conjs, *newconjs = NIL;
9249 RangeTblEntry *R_rte;
9251 Query *q_body = NULL;
9252 Node *neg_having = NULL;
9254 RangeTblEntry *d_rte;
9257 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree ||
9258 !q->jointree->quals || q->setOperations)
9260 if (list_length(q->jointree->fromlist) != 1 ||
9261 !IsA(linitial(q->jointree->fromlist), RangeTblRef))
9263 r_ref = (RangeTblRef *)linitial(q->jointree->fromlist);
9264 R_idx = r_ref->rtindex;
9265 R_rte = list_nth_node(RangeTblEntry, q->rtable, R_idx - 1);
9269 quals = q->jointree->quals;
9270 conjs = (IsA(quals, BoolExpr) && ((BoolExpr *)quals)->boolop == AND_EXPR)
9271 ? ((BoolExpr *)quals)->args
9272 : list_make1(quals);
9273 foreach (lc, conjs) {
9274 Node *c = (Node *)lfirst(lc);
9276 if (q_body == NULL && IsA(c, BoolExpr) &&
9277 ((BoolExpr *)c)->boolop == NOT_EXPR &&
9278 list_length(((BoolExpr *)c)->args) == 1) {
9280 Node *inner = (Node *)linitial(((BoolExpr *)c)->args);
9281 if (IsA(inner, SubLink) &&
9282 ((SubLink *)inner)->subLinkType == EXISTS_SUBLINK &&
9283 IsA(((SubLink *)inner)->subselect, Query) &&
9285 constants, (Query *)((SubLink *)inner)->subselect)) {
9286 Oid ge = OpernameGetOprid(list_make1(makeString(
">=")), INT8OID,
9288 q_body = (Query *)((SubLink *)inner)->subselect;
9291 (Node *)makeConst(INT8OID, -1, InvalidOid,
sizeof(int64),
9292 Int64GetDatum(1),
false, FLOAT8PASSBYVAL));
9295 }
else if (q_body == NULL && IsA(c, OpExpr) &&
9296 list_length(((OpExpr *)c)->args) == 2) {
9298 OpExpr *op = (OpExpr *)c;
9299 Node *l = (Node *)linitial(op->args), *r = (Node *)lsecond(op->args);
9303 if (IsA(l, SubLink) && IsA(r, Const) && !((Const *)r)->constisnull &&
9304 exprType(l) == INT8OID) {
9305 SubLink *sl = (SubLink *)l;
9307 if (sl->subLinkType == EXPR_SUBLINK && IsA(sl->subselect, Query)) {
9308 Query *s = (Query *)sl->subselect;
9309 TargetEntry *te = (list_length(s->targetList) == 1)
9310 ? (TargetEntry *)linitial(s->targetList)
9312 Aggref *cnt = (te && IsA(te->expr, Aggref)) ? (Aggref *)te->expr
9322 OidIsValid((neg = get_negator(op->opno)))) {
9325 neg, op->inputcollid, (Aggref *)copyObject(cnt), r);
9331 newconjs = lappend(newconjs, c);
9344 R_idx , &Rc, &Dc, NULL,
9346 lfirst(list_nth_cell(q->rtable, R_idx - 1)) =
9349 q->jointree->quals =
9352 : (list_length(newconjs) == 1
9353 ? (Node *)linitial(newconjs)
9354 : (Node *)makeBoolExpr(AND_EXPR, newconjs, -1));
9362 if (q->jointree->quals)
9365 q->hasSubLinks =
false;
9386 bool changed =
false;
9388 if (q->commandType != CMD_SELECT || !q->hasSubLinks || !q->jointree)
9391 foreach (lc, q->targetList) {
9392 TargetEntry *te = (TargetEntry *)lfirst(lc);
9395 RangeTblEntry *d_rte;
9400 if (!IsA(te->expr, SubLink))
9402 sl = (SubLink *)te->expr;
9403 if (sl->subLinkType != EXPR_SUBLINK || !IsA(sl->subselect, Query))
9412 rtr = makeNode(RangeTblRef);
9413 dte = (TargetEntry *)linitial(D->targetList);
9414 q->rtable = lappend(q->rtable, d_rte);
9415 d_idx = list_length(q->rtable);
9416 rtr->rtindex = d_idx;
9417 q->jointree->fromlist = lappend(q->jointree->fromlist, rtr);
9418 te->expr = (Expr *)makeVar(d_idx, 1, exprType((Node *)dte->expr),
9419 exprTypmod((Node *)dte->expr),
9420 exprCollation((Node *)dte->expr), 0);
9432 if (q->jointree->quals)
9435 q->hasSubLinks =
false;
9443 Node *n = limitCount;
9447 if (IsA(n, FuncExpr) && list_length(((FuncExpr *)n)->args) == 1)
9448 n = (Node *)linitial(((FuncExpr *)n)->args);
9449 if (IsA(n, RelabelType))
9450 n = (Node *)((RelabelType *)n)->arg;
9451 if (!IsA(n, Const) || ((Const *)n)->constisnull)
9454 if (c->consttype == INT8OID)
9455 return DatumGetInt64(c->constvalue) == 1;
9456 if (c->consttype == INT4OID)
9457 return DatumGetInt32(c->constvalue) == 1;
9458 if (c->consttype == INT2OID)
9459 return DatumGetInt16(c->constvalue) == 1;
9483#if PG_VERSION_NUM >= 160000
9484 return equal(rta, rtb);
9486 RangeTblEntry *a = (RangeTblEntry *)copyObject(linitial(rta));
9487 RangeTblEntry *b = (RangeTblEntry *)copyObject(linitial(rtb));
9488 a->requiredPerms = b->requiredPerms = 0;
9489 a->checkAsUser = b->checkAsUser = InvalidOid;
9490 a->selectedCols = b->selectedCols = NULL;
9491 a->insertedCols = b->insertedCols = NULL;
9492 a->updatedCols = b->updatedCols = NULL;
9493#if PG_VERSION_NUM >= 120000
9494 a->extraUpdatedCols = b->extraUpdatedCols = NULL;
9501 if (a->hasAggs || b->hasAggs || a->distinctClause || b->distinctClause ||
9502 a->sortClause || b->sortClause || a->limitCount || b->limitCount ||
9503 a->limitOffset || b->limitOffset)
9505 if (list_length(a->targetList) != 1 || list_length(b->targetList) != 1 ||
9506 list_length(a->rtable) != 1 || list_length(b->rtable) != 1)
9509 equal(a->jointree, b->jointree);
9525 Index R_idx, Q_idx, join_idx;
9526 RangeTblEntry *R_rte, *Q_rte_orig, *Q_copy, *jrte;
9529 TargetEntry *sl_te = NULL;
9536 int i, n_tl_sublinks = 0;
9537 bool in_where =
false;
9538 bool is_agg_body =
false;
9539 bool is_limit1 =
false;
9540 bool is_distinct =
false;
9541 bool coalesce =
false;
9542 List *co_sls = NIL, *co_tes = NIL;
9547 if (q->commandType != CMD_SELECT || !q->hasSubLinks)
9549 if (q->groupClause || q->groupingSets || q->hasAggs || q->distinctClause ||
9550 q->setOperations || q->havingQual || q->hasWindowFuncs)
9552 if (!q->jointree || q->jointree->fromlist == NIL)
9564 if (q->jointree->quals)
9575 foreach (lc, q->targetList) {
9576 TargetEntry *te = (TargetEntry *)lfirst(lc);
9578 if (te->expr == NULL || !IsA(te->expr, SubLink))
9580 e = (SubLink *)te->expr;
9581 if (e->subLinkType != EXPR_SUBLINK || !IsA(e->subselect, Query))
9584 rep = (Query *)e->subselect;
9587 co_sls = lappend(co_sls, e);
9588 co_tes = lappend(co_tes, te);
9594 sl = (SubLink *)linitial(co_sls);
9595 sl_te = (TargetEntry *)linitial(co_tes);
9600 if (sl == NULL || sl->subLinkType != EXPR_SUBLINK ||
9601 !IsA(sl->subselect, Query))
9607 foreach (lc, q->targetList) {
9608 TargetEntry *te = (TargetEntry *)lfirst(lc);
9609 if (te->expr == (Expr *)sl) {
9614 if (sl_te == NULL) {
9615 if (n_tl_sublinks > 0)
9625 if (!list_member_ptr(direct, sl))
9636 sub = (Query *)sl->subselect;
9637 if (sub->commandType != CMD_SELECT || sub->groupClause ||
9638 sub->groupingSets || sub->setOperations || sub->hasWindowFuncs ||
9639 sub->hasSubLinks || sub->limitOffset || sub->cteList)
9644 if (sub->distinctClause != NIL) {
9645 if (sub->hasDistinctOn || sub->hasAggs || sub->limitCount)
9652 if (sub->limitCount) {
9653 if (!sub->sortClause || sub->hasAggs ||
9663 foreach (tlc, sub->targetList)
9664 if (!((TargetEntry *)lfirst(tlc))->resjunk)
9666 if (nreal != 1 || ((TargetEntry *)linitial(sub->targetList))->resjunk)
9670 !IsA(((TargetEntry *)linitial(sub->targetList))->expr, Aggref))
9672 is_agg_body = sub->hasAggs;
9673 if (!sub->jointree || sub->jointree->fromlist == NIL)
9680 if (list_length(sub->jointree->fromlist) != 1 ||
9681 !IsA(linitial(sub->jointree->fromlist), RangeTblRef))
9683 Q_rte_orig = list_nth_node(RangeTblEntry, sub->rtable, 0);
9684 if ((Q_rte_orig->rtekind != RTE_RELATION &&
9685 !(Q_rte_orig->rtekind == RTE_SUBQUERY && !Q_rte_orig->lateral)) ||
9694 if (list_length(q->jointree->fromlist) == 1 &&
9695 IsA(linitial(q->jointree->fromlist), RangeTblRef)) {
9696 r_ref = (RangeTblRef *)linitial(q->jointree->fromlist);
9697 R_rte = list_nth_node(RangeTblEntry, q->rtable, r_ref->rtindex - 1);
9698 if ((R_rte->rtekind == RTE_RELATION ||
9699 (R_rte->rtekind == RTE_SUBQUERY && !R_rte->lateral)) &&
9701 R_idx = r_ref->rtindex;
9705 if (R_rte == NULL) {
9714 R_rte = list_nth_node(RangeTblEntry, q->rtable, 0);
9715 sub = (Query *)sl->subselect;
9719 foreach (lc, q->targetList) {
9720 TargetEntry *te = (TargetEntry *)lfirst(lc);
9721 if (te->expr == (Expr *)sl) {
9739 if (sub->jointree->quals)
9743 ((Aggref *)((TargetEntry *)linitial(sub->targetList))->expr)->aggstar))
9751 Q_copy = copyObject(Q_rte_orig);
9752#if PG_VERSION_NUM >= 160000
9753 if (Q_rte_orig->perminfoindex != 0) {
9754 RTEPermissionInfo *pi =
9755 getRTEPermissionInfo(sub->rteperminfos, Q_rte_orig);
9756 q->rteperminfos = lappend(q->rteperminfos, copyObject(pi));
9757 Q_copy->perminfoindex = list_length(q->rteperminfos);
9760 q->rtable = lappend(q->rtable, Q_copy);
9761 Q_idx = list_length(q->rtable);
9769 copyObject((Node *)((TargetEntry *)linitial(sub->targetList))->expr),
9775 List *av = NIL, *lcols = NIL, *rcols = NIL, *cn = NIL;
9776 jrte = makeNode(RangeTblEntry);
9777 for (i = 0; i < Rc.
n; ++i) {
9778 av = lappend(av, makeVar(R_idx, Rc.
attno[i], Rc.
type[i], Rc.
typmod[i],
9780 lcols = lappend_int(lcols, Rc.
attno[i]);
9781 rcols = lappend_int(rcols, 0);
9782 cn = lappend(cn, makeString(pstrdup(Rc.
name[i])));
9784 for (i = 0; i < Qc.
n; ++i) {
9785 av = lappend(av, makeVar(Q_idx, Qc.
attno[i], Qc.
type[i], Qc.
typmod[i],
9787 lcols = lappend_int(lcols, 0);
9788 rcols = lappend_int(rcols, Qc.
attno[i]);
9789 cn = lappend(cn, makeString(pstrdup(Qc.
name[i])));
9791 jrte->rtekind = RTE_JOIN;
9792 jrte->jointype = JOIN_LEFT;
9794 jrte->eref = makeAlias(
"unnamed_join", cn);
9795 jrte->joinaliasvars = av;
9796#if PG_VERSION_NUM >= 130000
9797 jrte->joinleftcols = lcols;
9798 jrte->joinrightcols = rcols;
9799 jrte->joinmergedcols = 0;
9801 jrte->inFromCl =
true;
9802 q->rtable = lappend(q->rtable, jrte);
9803 join_idx = list_length(q->rtable);
9807 JoinExpr *je = makeNode(JoinExpr);
9808 RangeTblRef *lr = makeNode(RangeTblRef), *rr = makeNode(RangeTblRef);
9809 lr->rtindex = R_idx;
9810 rr->rtindex = Q_idx;
9811 je->jointype = JOIN_LEFT;
9812 je->larg = (Node *)lr;
9813 je->rarg = (Node *)rr;
9815 je->isNatural =
false;
9816 je->usingClause = NIL;
9817 je->rtindex = join_idx;
9818 q->jointree->fromlist = list_make1(je);
9830 Aggref *agg = (Aggref *)valexpr;
9832 Var *qkey = (Var *)copyObject(scan.
found_var);
9833 qkey->varno = Q_idx;
9834#if PG_VERSION_NUM >= 130000
9836 qkey->varattnosyn = 0;
9841 repl_expr = valexpr;
9843 }
else if (is_limit1) {
9848 Aggref *agg = makeNode(Aggref);
9849 List *new_args = NIL;
9851 foreach (alc, sub->targetList) {
9852 TargetEntry *te = (TargetEntry *)copyObject(lfirst(alc));
9854 new_args = lappend(new_args, te);
9857 agg->aggtype = exprType((Node *)valexpr);
9858 agg->aggtranstype = InvalidOid;
9859 agg->aggargtypes = list_make1_oid(exprType((Node *)valexpr));
9860 agg->args = new_args;
9861 agg->aggorder = (List *)copyObject((Node *)sub->sortClause);
9862 agg->aggkind = AGGKIND_NORMAL;
9863 agg->aggsplit = AGGSPLIT_SIMPLE;
9865#if PG_VERSION_NUM >= 140000
9866 agg->aggno = agg->aggtransno = -1;
9868 repl_expr = (Expr *)agg;
9871 exprType((Node *)valexpr),
9872 exprType((Node *)valexpr), valexpr);
9880 forboth(la, co_sls, lb, co_tes) {
9881 SubLink *sli = (SubLink *)lfirst(la);
9882 TargetEntry *tei = (TargetEntry *)lfirst(lb);
9885 (Node *)((TargetEntry *)linitial(((Query *)sli->subselect)->targetList))
9889 exprType((Node *)vi),
9890 exprType((Node *)vi), vi);
9892 }
else if (!in_where)
9893 sl_te->expr = repl_expr;
9900 foreach (lc, q->targetList) {
9901 TargetEntry *te = (TargetEntry *)lfirst(lc);
9902 if (te->ressortgroupref > sgref)
9903 sgref = te->ressortgroupref;
9905 for (i = 0; i < Rc.
n; ++i) {
9906 TargetEntry *gte = NULL;
9907 SortGroupClause *sgc;
9911 foreach (lc2, q->targetList) {
9912 TargetEntry *te = (TargetEntry *)lfirst(lc2);
9913 if (IsA(te->expr, Var)) {
9914 Var *v = (Var *)te->expr;
9915 if (v->varlevelsup == 0 && v->varno == R_idx &&
9916 v->varattno == Rc.
attno[i]) {
9925 gte = makeTargetEntry((Expr *)v, list_length(q->targetList) + 1,
9926 pstrdup(Rc.
name[i]),
true );
9927 q->targetList = lappend(q->targetList, gte);
9929 if (gte->ressortgroupref == 0)
9930 gte->ressortgroupref = ++sgref;
9931 sgc = makeNode(SortGroupClause);
9932 sgc->tleSortGroupRef = gte->ressortgroupref;
9933 get_sort_group_operators(Rc.
type[i],
false,
true,
false, &sgc->sortop,
9934 &sgc->eqop, NULL, &sgc->hashable);
9935 q->groupClause = lappend(q->groupClause, sgc);
9946 List *having_conjuncts = NIL;
9948 if (!is_agg_body && !is_limit1) {
9951 having_conjuncts = list_make1(
9961 having_conjuncts = lappend(
9971 Node *quals = q->jointree->quals;
9973 (quals && IsA(quals, BoolExpr) &&
9974 ((BoolExpr *)quals)->boolop == AND_EXPR)
9975 ? ((BoolExpr *)quals)->args
9976 : (quals ? list_make1(quals) : NIL);
9982 foreach (lc2, conjs) {
9983 Node *c = (Node *)lfirst(lc2);
9988 kept = lappend(kept, c);
9990 q->jointree->quals =
9991 (kept == NIL) ? NULL
9992 : (list_length(kept) == 1 ? (Node *)linitial(kept)
9993 : (Node *)makeBoolExpr(
9994 AND_EXPR, kept, -1));
9998 (having_conjuncts == NIL)
10000 : (list_length(having_conjuncts) == 1
10001 ? (Node *)linitial(having_conjuncts)
10002 : (Node *)makeBoolExpr(AND_EXPR, having_conjuncts, -1));
10006 q->hasSubLinks =
false;
10040 SetOperationStmt *so;
10041 RangeTblRef *rarg_ref;
10042 RangeTblEntry *rarg_rte;
10044 RangeTblEntry *w_rte;
10049 int colno = 0, sgref = 0;
10050 bool any_group =
false;
10054 if (q->setOperations == NULL || !IsA(q->setOperations, SetOperationStmt))
10056 so = (SetOperationStmt *)q->setOperations;
10057 if (so->op != SETOP_EXCEPT)
10061 if (!IsA(so->rarg, RangeTblRef))
10063 rarg_ref = (RangeTblRef *)so->rarg;
10064 rarg_rte = list_nth_node(RangeTblEntry, q->rtable, rarg_ref->rtindex - 1);
10065 if (rarg_rte->rtekind != RTE_SUBQUERY || rarg_rte->subquery == NULL)
10067 origB = rarg_rte->subquery;
10072 if (origB->groupClause != NIL || origB->groupingSets != NIL)
10075 G = makeNode(Query);
10076 G->commandType = CMD_SELECT;
10077 G->canSetTag =
true;
10079 G->rtable = list_make1(w_rte);
10080 rtr = makeNode(RangeTblRef);
10082 fe = makeNode(FromExpr);
10083 fe->fromlist = list_make1(rtr);
10087 foreach (lc, origB->targetList) {
10088 TargetEntry *te = (TargetEntry *)lfirst(lc);
10091 SortGroupClause *sgc;
10098 coltype = exprType((Node *)te->expr);
10099 v = makeVar(1, colno, coltype, exprTypmod((Node *)te->expr),
10100 exprCollation((Node *)te->expr), 0);
10101 nte = makeTargetEntry((Expr *)v, list_length(tl) + 1,
10102 te->resname ? pstrdup(te->resname) : NULL,
false);
10106 sgc = makeNode(SortGroupClause);
10107 sgc->tleSortGroupRef = nte->ressortgroupref = ++sgref;
10108 get_sort_group_operators(coltype,
false,
true,
false, &sgc->sortop,
10109 &sgc->eqop, NULL, &sgc->hashable);
10110 G->groupClause = lappend(G->groupClause, sgc);
10113 tl = lappend(tl, nte);
10115 G->targetList = tl;
10120 rarg_rte->subquery = G;
10137 SetOperationStmt *stmt,
10139 if (stmt->op != SETOP_UNION) {
10142 if (IsA(stmt->larg, SetOperationStmt)) {
10145 if (IsA(stmt->rarg, SetOperationStmt)) {
10151 if (IsA(stmt->larg, RangeTblRef)) {
10152 Index rtindex = ((RangeTblRef *)stmt->larg)->rtindex;
10153 RangeTblEntry *rte = list_nth_node(RangeTblEntry, q->rtable, rtindex - 1);
10154 if (rte->rtekind == RTE_SUBQUERY && rte->subquery != NULL) {
10155 ListCell *lc_type = list_head(stmt->colTypes);
10156 ListCell *lc_te = list_head(rte->subquery->targetList);
10157 while (lc_type != NULL && lc_te != NULL) {
10158 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
10162 lc_type =
my_lnext(stmt->colTypes, lc_type);
10163 lc_te =
my_lnext(rte->subquery->targetList, lc_te);
10168 stmt->colTypes = lappend_oid(stmt->colTypes, constants->
OID_TYPE_UUID);
10169 stmt->colTypmods = lappend_int(stmt->colTypmods, -1);
10170 stmt->colCollations = lappend_int(stmt->colCollations, 0);
10188 FuncExpr *
gate_zero = makeNode(FuncExpr);
10189 OpExpr *oe = makeNode(OpExpr);
10196 oe->opresulttype = BOOLOID;
10200 if (q->jointree->quals != NULL) {
10201 BoolExpr *be = makeNode(BoolExpr);
10203 be->boolop = AND_EXPR;
10204 be->args = list_make2(oe, q->jointree->quals);
10207 q->jointree->quals = (Node *)be;
10209 q->jointree->quals = (Node *)oe;
10226 havingQual = (Node*) expr;
10227 }
else if(IsA(havingQual, BoolExpr) && ((BoolExpr*)havingQual)->boolop==AND_EXPR) {
10228 BoolExpr *be = (BoolExpr*)havingQual;
10229 be->args = lappend(be->args, expr);
10230 }
else if(IsA(havingQual, OpExpr) || IsA(havingQual, BoolExpr)) {
10232 BoolExpr *be = makeNode(BoolExpr);
10233 be->boolop=AND_EXPR;
10235 be->args = list_make2(havingQual, expr);
10236 havingQual = (Node*) be;
10238 provsql_error(
"Unknown structure within Boolean expression");
10260 if(op->args->length != 2)
10263 for(
unsigned i=0; i<2; ++i) {
10264 Node *arg = lfirst(list_nth_cell(op->args, i));
10275 return agg_sides >= 1;
10293 foreach (lc, be->args) {
10294 Node *n=lfirst(lc);
10301 if(IsA(n, OpExpr)) {
10304 }
else if(IsA(n, BoolExpr)) {
10322 switch(expr->type) {
10328 provsql_error(
"Unknown structure within Boolean expression");
10366 foreach (l, q->rtable) {
10367 RangeTblEntry *r = (RangeTblEntry *)lfirst(l);
10371 if (r->eref && r->eref->colnames != NIL) {
10374 columns[i] = (
int *)palloc(list_length(r->eref->colnames) *
sizeof(
int));
10376 foreach (lc, r->eref->colnames) {
10379 columns[i][j] = ++(*nbcols);
10381 const char *v = strVal(lfirst(lc));
10383 if (strcmp(v,
"") && r->rtekind != RTE_JOIN) {
10385 columns[i][j] = -1;
10387 columns[i][j] = ++(*nbcols);
10443 if (has_agg && has_rv)
10471 provsql_error(
"Unsupported aggregate comparison shape in the selection "
10478 provsql_error(
"Unsupported random_variable comparison shape in the "
10482 provsql_error(
"WHERE clause mixes agg_token (HAVING-style) and "
10483 "random_variable (per-tuple) comparisons inside the "
10484 "same Boolean expression; this combination is not "
10522 List *rv_cmps = NIL;
10525 if (!q->jointree || !q->jointree->quals)
10528 quals = q->jointree->quals;
10534 if (!IsA(quals, BoolExpr) || ((BoolExpr *)quals)->boolop != AND_EXPR) {
10541 q->jointree->quals = NULL;
10544 rv_cmps = lappend(rv_cmps,
10546 constants,
false));
10547 q->jointree->quals = NULL;
10561 BoolExpr *be = (BoolExpr *)quals;
10562 ListCell *cell, *prev;
10564 for (cell = list_head(be->args), prev = NULL; cell != NULL;) {
10565 Expr *conjunct = (Expr *)lfirst(cell);
10577 cell = list_head(be->args);
10580 rv_cmps = lappend(rv_cmps,
10582 constants,
false));
10587 cell = list_head(be->args);
10600 if (be->args == NIL)
10601 q->jointree->quals = NULL;
10602 else if (list_length(be->args) == 1)
10603 q->jointree->quals = (Node *)linitial(be->args);
10623 RangeTblEntry *rte;
10626 if (v->varno < 1 || v->varno > list_length(ctx->
query->rtable))
10629 rte = list_nth_node(RangeTblEntry, ctx->
query->rtable, v->varno - 1);
10630 if (rte->rtekind != RTE_SUBQUERY || rte->subquery == NULL)
10633 if (v->varattno < 1 || v->varattno > list_length(rte->subquery->targetList))
10636 te = list_nth_node(TargetEntry, rte->subquery->targetList, v->varattno - 1);
10637 if (IsA(te->expr, FuncExpr)) {
10638 FuncExpr *f = (FuncExpr *)te->expr;
10640 Const *aggtype_const = (Const *)lsecond(f->args);
10641 return DatumGetObjectId(aggtype_const->constvalue);
10652 Var *v = (Var *)lfirst(lc);
10654 HeapTuple castTuple;
10656 if (!OidIsValid(target))
10659 castTuple = SearchSysCache2(CASTSOURCETARGET,
10661 ObjectIdGetDatum(target));
10662 if (HeapTupleIsValid(castTuple)) {
10663 Form_pg_cast castForm = (Form_pg_cast)GETSTRUCT(castTuple);
10664 if (OidIsValid(castForm->castfunc)) {
10665 FuncExpr *fc = makeNode(FuncExpr);
10666 fc->funcid = castForm->castfunc;
10667 fc->funcresulttype = target;
10668 fc->funcretset =
false;
10669 fc->funcvariadic =
false;
10670 fc->funcformat = COERCE_IMPLICIT_CAST;
10671 fc->funccollid = InvalidOid;
10672 fc->inputcollid = InvalidOid;
10673 fc->args = list_make1(v);
10677 ReleaseSysCache(castTuple);
10687 foreach (lc, args) {
10688 if (IsA(lfirst(lc), Var) &&
10710 if (IsA(node, OpExpr)) {
10715 if (swapped != NULL)
10718 return (Node *)node;
10720 if (IsA(node, WindowFunc)) {
10722 return (Node *)node;
10724 if (IsA(node, CoalesceExpr)) {
10726 return (Node *)node;
10728 if (IsA(node, MinMaxExpr)) {
10730 return (Node *)node;
10732 if (IsA(node, NullIfExpr)) {
10734 return (Node *)node;
10746 QTW_DONT_COPY_QUERY | QTW_IGNORE_RC_SUBQUERIES);
10761 if (IsA(node, OpExpr)) {
10762 OpExpr *oe = (OpExpr *) node;
10763 Node *left = (Node *) linitial(oe->args);
10764 Node *right = (Node *) lsecond(oe->args);
10767 if (IsA(left, FuncExpr) &&
10768 (((FuncExpr *)left)->funcformat == COERCE_IMPLICIT_CAST ||
10769 ((FuncExpr *)left)->funcformat == COERCE_EXPLICIT_CAST) &&
10770 list_length(((FuncExpr *)left)->args) == 1)
10771 left = linitial(((FuncExpr *)left)->args);
10772 if (IsA(right, FuncExpr) &&
10773 (((FuncExpr *)right)->funcformat == COERCE_IMPLICIT_CAST ||
10774 ((FuncExpr *)right)->funcformat == COERCE_EXPLICIT_CAST) &&
10775 list_length(((FuncExpr *)right)->args) == 1)
10776 right = linitial(((FuncExpr *)right)->args);
10778 if (IsA(left, Var) && IsA(right, Var)) {
10779 Var *left_var = (Var *)left;
10780 Var *right_var = (Var *)right;
10783 *ctx->
rteid = left_var->varno;
10789 *ctx->
rteid = right_var->varno;
10814 Index *rteid, AttrNumber *join_attno)
10837 Const *idx = makeConst(INT4OID, -1, InvalidOid,
sizeof(int32),
10838 Int32GetDatum(index),
false,
true);
10839#if PG_VERSION_NUM >= 120000
10840 SubscriptingRef *sub = makeNode(SubscriptingRef);
10843#if PG_VERSION_NUM >= 140000
10846 sub->reftypmod = -1;
10847 sub->refcollid = InvalidOid;
10848 sub->refupperindexpr = list_make1(idx);
10849 sub->reflowerindexpr = NIL;
10850 sub->refexpr = (Expr *)arr_expr;
10851 sub->refassgnexpr = NULL;
10852 return (Node *)sub;
10854 ArrayRef *sub = makeNode(ArrayRef);
10857 sub->reftypmod = -1;
10858 sub->refcollid = InvalidOid;
10859 sub->refupperindexpr = list_make1(idx);
10860 sub->reflowerindexpr = NIL;
10861 sub->refexpr = (Expr *)arr_expr;
10862 sub->refassgnexpr = NULL;
10863 return (Node *)sub;
10893 if (IsA(node, OpExpr)) {
10894 OpExpr *oe = (OpExpr *)node;
10895 if (list_length(oe->args) == 2) {
10896 Node *left = (Node *)linitial(oe->args);
10897 Node *right = (Node *)lsecond(oe->args);
10899 bool agg_on_left =
false;
10901 if (IsA(left, Var)) {
10902 Var *v = (Var *)left;
10903 if (v->varlevelsup == 0 && v->varno == ctx->
rteid &&
10907 agg_on_left =
true;
10910 if (agg_v == NULL && IsA(right, Var)) {
10911 Var *v = (Var *)right;
10912 if (v->varlevelsup == 0 && v->varno == ctx->
rteid &&
10919 if (agg_v != NULL) {
10920 Node *other = agg_on_left ? right : left;
10923 Form_pg_operator opform;
10925 agg_v->vartype = TEXTOID;
10926 agg_v->varcollid = DEFAULT_COLLATION_OID;
10928 if (exprType(other) != TEXTOID) {
10929 CoerceViaIO *c = makeNode(CoerceViaIO);
10930 c->arg = (Expr *)other;
10931 c->resulttype = TEXTOID;
10932 c->resultcollid = DEFAULT_COLLATION_OID;
10933 c->coerceformat = COERCE_EXPLICIT_CAST;
10939 oe->args = list_make2(agg_v, other);
10941 oe->args = list_make2(other, agg_v);
10944 if (!OidIsValid(text_eq))
10945 provsql_error(
"rewrite_join_agg_token: text = text operator "
10947 opInfo = SearchSysCache1(OPEROID, ObjectIdGetDatum(text_eq));
10948 if (!HeapTupleIsValid(opInfo))
10950 "text equality operator");
10951 opform = (Form_pg_operator)GETSTRUCT(opInfo);
10952 oe->opno = text_eq;
10953 oe->opfuncid = opform->oprcode;
10954 oe->opresulttype = opform->oprresult;
10955 oe->inputcollid = DEFAULT_COLLATION_OID;
10956 ReleaseSysCache(opInfo);
10964 if (IsA(node, Var)) {
10965 Var *v = (Var *)node;
10966 if (v->varlevelsup == 0 && v->varno == ctx->
rteid &&
10969 v->vartype = TEXTOID;
10970 v->varcollid = DEFAULT_COLLATION_OID;
10975 if (IsA(node, Query)) {
11016 Index rteid, AttrNumber join_attno)
11018 RangeTblEntry *src_rte = (RangeTblEntry *)list_nth(q->rtable, rteid - 1);
11019 AttrNumber provsql_attno = 0;
11023 RangeTblEntry *inner_src, *sm_rte;
11024 RangeTblFunction *rtfunc;
11025 FuncExpr *unnest_call, *get_children_of_agg, *agg_to_uuid;
11026 Var *agg_var_in_inner;
11027 Alias *sm_alias, *sm_eref;
11028 RangeTblRef *inner_rtr1, *inner_rtr2;
11029 FromExpr *inner_jt;
11030 List *inner_tl = NIL;
11032 if (src_rte->rtekind != RTE_RELATION && src_rte->rtekind != RTE_SUBQUERY)
11033 provsql_error(
"rewrite_join_agg_token: source RTE kind %d not supported",
11034 (
int)src_rte->rtekind);
11038 foreach (lc, src_rte->eref->colnames) {
11040 provsql_attno = attno;
11045 if (provsql_attno == 0)
11046 provsql_error(
"rewrite_join_agg_token: source relation has no "
11051 agg_var_in_inner = makeNode(Var);
11052 agg_var_in_inner->varno = 1;
11053 agg_var_in_inner->varattno = join_attno;
11055 agg_var_in_inner->varcollid = InvalidOid;
11056 agg_var_in_inner->vartypmod = -1;
11057 agg_var_in_inner->location = -1;
11059 agg_to_uuid = makeNode(FuncExpr);
11062 agg_to_uuid->funcretset =
false;
11063 agg_to_uuid->funcvariadic =
false;
11064 agg_to_uuid->funcformat = COERCE_IMPLICIT_CAST;
11065 agg_to_uuid->funccollid = InvalidOid;
11066 agg_to_uuid->inputcollid = InvalidOid;
11067 agg_to_uuid->args = list_make1(agg_var_in_inner);
11068 agg_to_uuid->location = -1;
11070 get_children_of_agg = makeNode(FuncExpr);
11073 get_children_of_agg->funcretset =
false;
11074 get_children_of_agg->funcvariadic =
false;
11075 get_children_of_agg->funcformat = COERCE_EXPLICIT_CALL;
11076 get_children_of_agg->funccollid = InvalidOid;
11077 get_children_of_agg->inputcollid = InvalidOid;
11078 get_children_of_agg->args = list_make1(agg_to_uuid);
11079 get_children_of_agg->location = -1;
11081 unnest_call = makeNode(FuncExpr);
11082 unnest_call->funcid = constants->
OID_UNNEST;
11084 unnest_call->funcretset =
true;
11085 unnest_call->funcvariadic =
false;
11086 unnest_call->funcformat = COERCE_EXPLICIT_CALL;
11087 unnest_call->funccollid = InvalidOid;
11088 unnest_call->inputcollid = InvalidOid;
11089 unnest_call->args = list_make1(get_children_of_agg);
11090 unnest_call->location = -1;
11092 rtfunc = makeNode(RangeTblFunction);
11093 rtfunc->funcexpr = (Node *)unnest_call;
11094 rtfunc->funccolcount = 1;
11095 rtfunc->funccolnames = NIL;
11096 rtfunc->funccoltypes = NIL;
11097 rtfunc->funccoltypmods = NIL;
11098 rtfunc->funccolcollations = NIL;
11099 rtfunc->funcparams = NULL;
11101 sm_alias = makeNode(Alias);
11102 sm_eref = makeNode(Alias);
11103 sm_alias->aliasname =
"sm";
11104 sm_eref->aliasname =
"sm";
11105 sm_eref->colnames = list_make1(makeString(
"sm"));
11107 sm_rte = makeNode(RangeTblEntry);
11108 sm_rte->rtekind = RTE_FUNCTION;
11109 sm_rte->functions = list_make1(rtfunc);
11110 sm_rte->funcordinality =
false;
11111 sm_rte->alias = sm_alias;
11112 sm_rte->eref = sm_eref;
11113 sm_rte->lateral =
true;
11114 sm_rte->inFromCl =
true;
11115#if PG_VERSION_NUM < 160000
11116 sm_rte->requiredPerms = 0;
11121 inner_src = copyObject(src_rte);
11129 inner_rtr1 = makeNode(RangeTblRef);
11130 inner_rtr1->rtindex = 1;
11131 inner_rtr2 = makeNode(RangeTblRef);
11132 inner_rtr2->rtindex = 2;
11133 inner_jt = makeNode(FromExpr);
11134 inner_jt->fromlist = list_make2(inner_rtr1, inner_rtr2);
11135 inner_jt->quals = NULL;
11140 foreach (lc, src_rte->eref->colnames) {
11141 const char *colname = strVal(lfirst(lc));
11142 TargetEntry *te = makeNode(TargetEntry);
11144 te->resname = pstrdup(colname);
11145 te->resjunk =
false;
11147 if (attno == join_attno) {
11149 Var *sm_var = makeNode(Var);
11150 FuncExpr *gch, *ge;
11154 sm_var->varattno = 1;
11156 sm_var->varcollid = InvalidOid;
11157 sm_var->vartypmod = -1;
11158 sm_var->location = -1;
11160 gch = makeNode(FuncExpr);
11163 gch->funcretset =
false;
11164 gch->funcvariadic =
false;
11165 gch->funcformat = COERCE_EXPLICIT_CALL;
11166 gch->funccollid = InvalidOid;
11167 gch->inputcollid = InvalidOid;
11168 gch->args = list_make1(sm_var);
11169 gch->location = -1;
11173 ge = makeNode(FuncExpr);
11175 ge->funcresulttype = TEXTOID;
11176 ge->funcretset =
false;
11177 ge->funcvariadic =
false;
11178 ge->funcformat = COERCE_EXPLICIT_CALL;
11179 ge->funccollid = DEFAULT_COLLATION_OID;
11180 ge->inputcollid = InvalidOid;
11181 ge->args = list_make1(subscript);
11184 te->expr = (Expr *)ge;
11185 }
else if (attno == provsql_attno) {
11187 Var *sm_var = makeNode(Var);
11188 Var *prov_var = makeNode(Var);
11189 FuncExpr *gch, *pt;
11194 sm_var->varattno = 1;
11196 sm_var->varcollid = InvalidOid;
11197 sm_var->vartypmod = -1;
11198 sm_var->location = -1;
11200 gch = makeNode(FuncExpr);
11203 gch->funcretset =
false;
11204 gch->funcvariadic =
false;
11205 gch->funcformat = COERCE_EXPLICIT_CALL;
11206 gch->funccollid = InvalidOid;
11207 gch->inputcollid = InvalidOid;
11208 gch->args = list_make1(sm_var);
11209 gch->location = -1;
11213 prov_var->varno = 1;
11214 prov_var->varattno = provsql_attno;
11216 prov_var->varcollid = InvalidOid;
11217 prov_var->vartypmod = -1;
11218 prov_var->location = -1;
11220 arr = makeNode(ArrayExpr);
11223 arr->elements = list_make2(subscript, prov_var);
11224 arr->location = -1;
11226 pt = makeNode(FuncExpr);
11229 pt->funcretset =
false;
11230 pt->funcvariadic =
true;
11231 pt->funcformat = COERCE_EXPLICIT_CALL;
11232 pt->funccollid = InvalidOid;
11233 pt->inputcollid = InvalidOid;
11234 pt->args = list_make1(arr);
11237 te->expr = (Expr *)pt;
11240 Var *v = makeNode(Var);
11241 Oid vtype = InvalidOid;
11242 int32 vtypmod = -1;
11243 Oid vcoll = InvalidOid;
11245 if (src_rte->rtekind == RTE_RELATION) {
11246 get_atttypetypmodcoll(src_rte->relid, attno, &vtype, &vtypmod, &vcoll);
11248 TargetEntry *sub_te =
11249 (TargetEntry *)list_nth(src_rte->subquery->targetList, attno - 1);
11250 vtype = exprType((Node *)sub_te->expr);
11251 vtypmod = exprTypmod((Node *)sub_te->expr);
11252 vcoll = exprCollation((Node *)sub_te->expr);
11256 v->varattno = attno;
11257 v->vartype = vtype;
11258 v->varcollid = vcoll;
11259 v->vartypmod = vtypmod;
11261 te->expr = (Expr *)v;
11264 inner_tl = lappend(inner_tl, te);
11268 inner = makeNode(Query);
11269 inner->commandType = CMD_SELECT;
11270 inner->canSetTag =
true;
11271 inner->rtable = list_make2(inner_src, sm_rte);
11272 inner->jointree = inner_jt;
11273 inner->targetList = inner_tl;
11274 inner->hasAggs =
false;
11275 inner->hasSubLinks =
false;
11277#if PG_VERSION_NUM >= 160000
11283 if (inner_src->perminfoindex != 0) {
11284 RTEPermissionInfo *perminfo =
11285 getRTEPermissionInfo(q->rteperminfos, src_rte);
11286 inner->rteperminfos = list_make1(copyObject(perminfo));
11287 inner_src->perminfoindex = 1;
11293 src_rte->rtekind = RTE_SUBQUERY;
11294 src_rte->subquery = inner;
11295 src_rte->relid = InvalidOid;
11296 src_rte->relkind = 0;
11297#if PG_VERSION_NUM >= 120000
11298 src_rte->rellockmode = 0;
11300 src_rte->inh =
false;
11301 src_rte->lateral =
false;
11302#if PG_VERSION_NUM >= 160000
11303 src_rte->perminfoindex = 0;
11305 src_rte->selectedCols = NULL;
11306 src_rte->insertedCols = NULL;
11307 src_rte->updatedCols = NULL;
11308 src_rte->requiredPerms = ACL_SELECT;
11319 ListCell *cell, *prev;
11324 for (cell = list_head(src_rte->eref->colnames); cell != NULL; ) {
11325 if (i == provsql_attno) {
11326 src_rte->eref->colnames =
11331 cell =
my_lnext(src_rte->eref->colnames, cell);
11344 QTW_IGNORE_RT_SUBQUERIES);
11370 FuncExpr *wrap = makeNode(FuncExpr);
11373 wrap->funcretset =
false;
11374 wrap->funcvariadic =
false;
11375 wrap->funcformat = COERCE_EXPLICIT_CALL;
11376 wrap->funccollid = InvalidOid;
11377 wrap->inputcollid = InvalidOid;
11378 wrap->args = list_make1(expr);
11379 wrap->location = -1;
11380 return (Expr *) wrap;
11394 const char *cert) {
11395 FuncExpr *wrap = makeNode(FuncExpr);
11396 Const *ce = makeConst(TEXTOID, -1, DEFAULT_COLLATION_OID, -1,
11397 CStringGetTextDatum(cert),
false,
false);
11400 wrap->funcretset =
false;
11401 wrap->funcvariadic =
false;
11402 wrap->funcformat = COERCE_EXPLICIT_CALL;
11403 wrap->funccollid = InvalidOid;
11404 wrap->inputcollid = DEFAULT_COLLATION_OID;
11405 wrap->args = list_make2(expr, (Expr *) ce);
11406 wrap->location = -1;
11407 return (Expr *) wrap;
11422 FuncExpr *wrap = makeNode(FuncExpr);
11425 wrap->funcretset =
false;
11426 wrap->funcvariadic =
false;
11427 wrap->funcformat = COERCE_EXPLICIT_CALL;
11428 wrap->funccollid = InvalidOid;
11429 wrap->inputcollid = InvalidOid;
11430 wrap->args = list_make2(target, evidence);
11431 wrap->location = -1;
11432 return (Expr *) wrap;
11437#if PG_VERSION_NUM >= 160000
11438 if (r->perminfoindex != 0) {
11439 RTEPermissionInfo *rpi =
11440 list_nth_node(RTEPermissionInfo, q->rteperminfos, r->perminfoindex - 1);
11441 rpi->selectedCols = bms_add_member(
11442 rpi->selectedCols, attno - FirstLowInvalidHeapAttributeNumber);
11445 r->selectedCols = bms_add_member(r->selectedCols,
11446 attno - FirstLowInvalidHeapAttributeNumber);
11453 AttrNumber attno) {
11454 Oid typid; int32 typmod; Oid coll;
11456 get_atttypetypmodcoll(r->relid, attno, &typid, &typmod, &coll);
11457 v = makeVar(relid, attno, typid, typmod, coll, 0);
11465 CoerceViaIO *c = makeNode(CoerceViaIO);
11467 c->resulttype = TEXTOID;
11468 c->resultcollid = DEFAULT_COLLATION_OID;
11469 c->coerceformat = COERCE_IMPLICIT_CAST;
11484 Index relid = prov_var->varno;
11485 RangeTblEntry *r = list_nth_node(RangeTblEntry, q->rtable, relid - 1);
11487 Const *factorc = makeConst(INT4OID, -1, InvalidOid,
sizeof(int32),
11488 Int32GetDatum(m->
factor),
false,
true);
11489 FuncExpr *keyf = makeNode(FuncExpr);
11490 FuncExpr *ann = makeNode(FuncExpr);
11497 secarg = (Expr *) makeConst(TEXTOID, -1, DEFAULT_COLLATION_OID, -1,
11498 CStringGetTextDatum(
"0"),
false,
false);
11504 keyf->funcresulttype = TEXTOID;
11505 keyf->funcretset =
false;
11506 keyf->funcvariadic =
false;
11507 keyf->funcformat = COERCE_EXPLICIT_CALL;
11508 keyf->funccollid = DEFAULT_COLLATION_OID;
11509 keyf->inputcollid = DEFAULT_COLLATION_OID;
11513 keyf->location = -1;
11517 ann->funcretset =
false;
11518 ann->funcvariadic =
false;
11519 ann->funcformat = COERCE_EXPLICIT_CALL;
11520 ann->funccollid = InvalidOid;
11521 ann->inputcollid = DEFAULT_COLLATION_OID;
11522 ann->args = list_make2((Expr *) prov_var, (Expr *) keyf);
11523 ann->location = -1;
11524 return (Expr *) ann;
11536 foreach (lc, prov_atts) {
11537 Node *n = (Node *) lfirst(lc);
11539 Var *pv = (Var *) n;
11540 if (pv->varno >= 1 && (
int) pv->varno <= natoms
11541 && markers[pv->varno - 1].
valid)
11543 &markers[pv->varno - 1]);
11594 if (IsA(node, Var)) {
11595 Var *v = (Var *) node;
11596 if (v->varlevelsup == 0) {
11599 if ((
int) v->varno >= 1 && (
int) v->varno <= c->
sub_rtlen[i]
11601 Var *nv = (Var *) copyObject(v);
11603 return (Node *) nv;
11605 }
else if ((
int) v->varno >= 1 && (
int) v->varno <= c->
N) {
11606 int i = (int) v->varno;
11608 if (v->varattno >= 1 && v->varattno <= c->
sub_tl_n[i]
11609 && c->
sub_tl[i][v->varattno] != NULL) {
11610 Var *base = c->
sub_tl[i][v->varattno];
11611 Var *nv = (Var *) copyObject(base);
11613 nv->varlevelsup = 0;
11614 return (Node *) nv;
11617 Var *nv = (Var *) copyObject(v);
11619 return (Node *) nv;
11623 return (Node *) copyObject(v);
11625 return expression_tree_mutator(node,
flatten_mut, cp);
11632 o->
path = (
int *) palloc(
sizeof(
int));
11642 o->
path = (
int *) palloc(o->
depth *
sizeof(
int));
11644 for (d = 0; d < sub->
depth; d++)
11676 int N = list_length(probe->rtable);
11678 List *new_rtable = NIL;
11679 List *origins_l = NIL;
11680 List *merged_quals = NIL;
11681 bool any_flat =
false, parent_flat = (probe->jointree != NULL);
11687 c.
slot_flat = (
bool *) palloc0((N + 1) *
sizeof(
bool));
11689 c.
sub_newpos = (
int **) palloc0((N + 1) *
sizeof(
int *));
11690 c.
sub_rtlen = (
int *) palloc0((N + 1) *
sizeof(
int));
11691 c.
sub_tl = (Var ***) palloc0((N + 1) *
sizeof(Var **));
11692 c.
sub_tl_n = (
int *) palloc0((N + 1) *
sizeof(
int));
11697 foreach (lc, probe->jointree->fromlist)
11698 if (!IsA((Node *) lfirst(lc), RangeTblRef)) { parent_flat =
false;
break; }
11702 for (i = 1; parent_flat && i <= N; i++) {
11703 RangeTblEntry *rte = list_nth_node(RangeTblEntry, probe->rtable, i - 1);
11712 if (!(rte->rtekind == RTE_SUBQUERY && rte->subquery != NULL && !rte->lateral)) {
11714 new_rtable = lappend(new_rtable, rte);
11719 sq = rte->subquery;
11720 ok = !(sq->commandType != CMD_SELECT
11721 || sq->setOperations || sq->hasAggs || sq->hasWindowFuncs
11722 || sq->groupingSets || sq->groupClause || sq->havingQual
11723 || sq->distinctClause || sq->hasDistinctOn || sq->hasSubLinks
11724 || sq->limitCount || sq->limitOffset || sq->cteList
11725 || sq->jointree == NULL);
11727 foreach (lc2, sq->jointree->fromlist)
11728 if (!IsA((Node *) lfirst(lc2), RangeTblRef)) { ok =
false;
break; }
11739 foreach (lc2, sq->rtable) {
11740 RangeTblEntry *br = (RangeTblEntry *) lfirst(lc2);
11741 if (br->rtekind == RTE_RELATION && br->relkind == RELKIND_VIEW)
11743 else if (br->rtekind == RTE_RELATION) realbase++;
11744 else { ok =
false;
break; }
11746 if (realbase < 1) ok =
false;
11750 foreach (lc2, sq->targetList) {
11751 TargetEntry *te = (TargetEntry *) lfirst(lc2);
11752 if (!te->resjunk && te->resno > maxres) maxres = te->resno;
11754 tl = ok ? (Var **) palloc0((maxres + 1) *
sizeof(Var *)) : NULL;
11756 foreach (lc2, sq->targetList) {
11757 TargetEntry *te = (TargetEntry *) lfirst(lc2);
11760 if (te->resjunk)
continue;
11761 if (!IsA(te->expr, Var)) { ok =
false;
break; }
11762 v = (Var *) te->expr;
11763 if (v->varlevelsup != 0
11764 || (
int) v->varno < 1 || (
int) v->varno > list_length(sq->rtable)) {
11767 br = list_nth_node(RangeTblEntry, sq->rtable, v->varno - 1);
11768 if (!(br->rtekind == RTE_RELATION && br->relkind != RELKIND_VIEW)) {
11779 new_rtable = lappend(new_rtable, rte);
11787 c.
sub_rtlen[i] = list_length(sq->rtable);
11792 foreach (lc2, sq->rtable) {
11793 RangeTblEntry *br = (RangeTblEntry *) lfirst(lc2);
11795 if (br->rtekind == RTE_RELATION && br->relkind != RELKIND_VIEW) {
11797 new_rtable = lappend(new_rtable, copyObject(br));
11802 origins_l = lappend(origins_l,
11803 (sub_origins != NULL && b - 1 < sub_n)
11811 if (parent_flat && any_flat) {
11813 probe->targetList = (List *)
flatten_mut((Node *) probe->targetList, &c);
11814 if (probe->jointree->quals)
11815 merged_quals = lappend(merged_quals,
flatten_mut(probe->jointree->quals, &c));
11817 for (i = 1; i <= N; i++) {
11818 RangeTblEntry *rte;
11820 rte = list_nth_node(RangeTblEntry, probe->rtable, i - 1);
11821 if (rte->subquery->jointree && rte->subquery->jointree->quals) {
11824 lappend(merged_quals,
11825 flatten_mut((Node *) copyObject(rte->subquery->jointree->quals),
11831 probe->rtable = new_rtable;
11834 for (i = 1; i <= newpos; i++) {
11835 RangeTblRef *r = makeNode(RangeTblRef);
11837 fl = lappend(fl, r);
11839 probe->jointree->fromlist = fl;
11841 probe->jointree->quals =
11842 (merged_quals == NIL) ? NULL
11843 : (list_length(merged_quals) == 1) ? (Node *) linitial(merged_quals)
11844 : (Node *) makeBoolExpr(AND_EXPR, merged_quals, -1);
11846 *nflat_out = newpos;
11849 foreach (lc, origins_l)
11858 for (i = 0; i < N; i++) {
11859 origins[i].
depth = 1;
11860 origins[i].
path = (
int *) palloc(
sizeof(
int));
11861 origins[i].
path[0] = i + 1;
11879 Query *q,
char **cert_out) {
11880 bool has_subq =
false, has_group =
false;
11884 int nflat = 0, norigins = 0, N, p;
11889 foreach (lc, q->rtable)
11890 if (((RangeTblEntry *) lfirst(lc))->rtekind == RTE_SUBQUERY) has_subq =
true;
11891#if PG_VERSION_NUM >= 180000
11892 has_group = q->hasGroupRTE;
11898 if (!has_subq && !has_group) {
11901 probe = (Query *) copyObject(q);
11902#if PG_VERSION_NUM >= 180000
11917 N = list_length(q->rtable);
11928 for (p = 0; p < nflat; p++) {
11931 int depth, d, base;
11934 if (!flat[p].valid)
11936 if (origins != NULL) {
11937 if (p >= norigins)
continue;
11938 path = origins[p].
path;
11939 depth = origins[p].
depth;
11941 tmp_path[0] = p + 1;
11946 for (d = 0; d + 1 < depth && cur != NULL; d++) {
11947 int slot = path[d];
11948 RangeTblEntry *rte;
11951 if (slot < 1 || slot > qcur->rtable->length) { cur = NULL;
break; }
11952 rte = list_nth_node(RangeTblEntry, qcur->rtable, slot - 1);
11953 if (rte->rtekind != RTE_SUBQUERY || rte->subquery == NULL) { cur = NULL;
break; }
11954 sublen = list_length(rte->subquery->rtable);
11955 child = cur->
sub[slot - 1];
11956 if (child == NULL) {
11961 cur->
sub[slot - 1] = child;
11964 qcur = rte->subquery;
11968 base = path[depth - 1];
11969 if (base >= 1 && base - 1 < cur->
natoms)
11970 cur->
markers[base - 1] = flat[p];
12004 TargetEntry *value = NULL;
12007 foreach (lc, sub->targetList) {
12008 TargetEntry *te = (TargetEntry *)lfirst(lc);
12018 kept = list_make1(value);
12019 foreach (lc, sub->targetList) {
12020 TargetEntry *te = (TargetEntry *)lfirst(lc);
12021 if (te != value && te->resjunk)
12022 kept = lappend(kept, te);
12025 ((TargetEntry *)lfirst(lc))->resno = ++n;
12026 sub->targetList = kept;
12033 if (IsA(node, SubLink)) {
12034 SubLink *sl = (SubLink *)node;
12035 if (sl->subLinkType == EXPR_SUBLINK && sl->subselect &&
12036 IsA(sl->subselect, Query) &&
12038 (Query *)sl->subselect)) {
12039 bool *removed = NULL;
12041 &removed,
false,
false,
false, NULL);
12043 sl->subselect = (Node *)processed;
12049 return expression_tree_walker((Node *) sl->testexpr,
12052 if (IsA(node, Query))
12106 bool **removed,
bool wrap_root,
bool top_level,
12107 bool in_boolean_rewrite,
12110 bool has_union =
false;
12111 bool has_difference =
false;
12112 bool supported =
true;
12113 bool group_by_rewrite =
false;
12115 int **columns = NULL;
12116 int columns_len = 0;
12118 char *inv_cert = NULL;
12120 List *given_evidence = NIL;
12122 elog_node_display(NOTICE,
"ProvSQL: Before query rewriting", q,
true);
12152 if (q->rtable == NULL) {
12163 if (rv_cmps != NIL) {
12165 RangeTblEntry *values_rte;
12169 if (list_length(rv_cmps) == 1) {
12173 FuncExpr *times = makeNode(FuncExpr);
12174 ArrayExpr *array = makeNode(ArrayExpr);
12177 times->funcvariadic =
true;
12178 times->location = -1;
12181 array->elements = rv_cmps;
12182 array->location = -1;
12183 times->args = list_make1(array);
12196 values_rte = makeNode(RangeTblEntry);
12197 values_rte->rtekind = RTE_VALUES;
12198 values_rte->values_lists = list_make1(list_make1(
provenance));
12199 values_rte->coltypes = list_make1_oid(constants->
OID_TYPE_UUID);
12200 values_rte->coltypmods = list_make1_int(-1);
12201 values_rte->colcollations = list_make1_oid(InvalidOid);
12202 values_rte->eref = makeAlias(
12205 values_rte->inh =
false;
12206 values_rte->inFromCl =
true;
12207#if PG_VERSION_NUM < 160000
12208 values_rte->requiredPerms = 0;
12210 q->rtable = list_make1(values_rte);
12212 rtr = makeNode(RangeTblRef);
12214 if (q->jointree == NULL) {
12215 q->jointree = makeNode(FromExpr);
12217 q->jointree->fromlist = list_make1(rtr);
12219 v = makeVar(1, 1, constants->
OID_TYPE_UUID, -1, InvalidOid, 0);
12228 TargetEntry *te = makeTargetEntry(
12229 (Expr *)copyObject(v),
12230 list_length(q->targetList) + 1,
12233 q->targetList = lappend(q->targetList, te);
12283 Bitmapset *removed_sortgrouprefs = NULL;
12285 if (q->targetList) {
12286 removed_sortgrouprefs =
12288 if (removed_sortgrouprefs != NULL)
12290 if (q->setOperations)
12305 if (given_evidence != NIL &&
12306 (q->hasAggs || q->groupClause || q->groupingSets || q->havingQual ||
12307 q->distinctClause || q->setOperations || q->hasWindowFuncs))
12309 "provsql.given (whole-tuple output conditioning) is supported only in "
12310 "a plain per-row SELECT, not in an aggregated / grouped / DISTINCT / "
12311 "set-operation query; condition the individual tokens with the binary "
12312 "| operator instead");
12316 if (q->setOperations) {
12320 SetOperationStmt *stmt = (SetOperationStmt *)q->setOperations;
12326 foreach (lc_rte, q->rtable) {
12327 RangeTblEntry *rte = (RangeTblEntry *)lfirst(lc_rte);
12328 if (rte->rtekind == RTE_SUBQUERY && rte->subquery &&
12329 rte->subquery->hasAggs)
12331 "aggregate results not supported");
12334 return process_query(constants, q, removed, wrap_root, top_level,
12335 in_boolean_rewrite, inv_ctx);
12342 return process_query(constants, rewritten, removed, wrap_root, top_level,
12343 in_boolean_rewrite, inv_ctx);
12351 AttrNumber join_attno;
12358 return process_query(constants, rewritten, removed, wrap_root,
12359 top_level, in_boolean_rewrite, inv_ctx);
12387 return process_query(constants, rewritten, removed,
true, top_level,
12400 if (inv_ctx != NULL) {
12404 local_inv_ctx = inv_ctx;
12433 if (local_inv_ctx != NULL && local_inv_ctx->
markers != NULL)
12437 if (prov_atts == NIL) {
12444 if (q->jointree && q->jointree->quals &&
12446 FuncExpr *one_expr = makeNode(FuncExpr);
12449 one_expr->args = NIL;
12450 one_expr->location = -1;
12451 prov_atts = list_make1(one_expr);
12469 bool has_direct =
false;
12471 if (has_direct || nested == NIL) {
12472 provsql_error(
"Subqueries (EXISTS, IN, scalar subquery) not supported");
12476 "scalar subquery nested in an expression is not tracked; its data is "
12477 "treated as certain and the result keeps only the outer provenance");
12484 if (supported && q->distinctClause)
12487 if (supported && q->setOperations) {
12488 SetOperationStmt *stmt = (SetOperationStmt *)q->setOperations;
12490 if (stmt->op == SETOP_UNION) {
12493 }
else if (stmt->op == SETOP_EXCEPT) {
12496 has_difference =
true;
12498 provsql_error(
"Set operations other than UNION and EXCEPT not "
12504 if (supported && q->groupClause &&
12506 group_by_rewrite =
true;
12509 if (supported && q->groupingSets) {
12510 if (q->groupClause || list_length(q->groupingSets) > 1 ||
12511 ((GroupingSet *)linitial(q->groupingSets))->kind !=
12512 GROUPING_SET_EMPTY) {
12513 provsql_error(
"GROUPING SETS, CUBE, and ROLLUP not supported");
12517 group_by_rewrite =
true;
12527 columns_len = q->rtable->length;
12528 columns = (
int **)palloc0(columns_len *
sizeof(
int *));
12542 if (q->hasWindowFuncs)
12544 "tracked per input row only, and the windowed "
12545 "computation is treated as an opaque scalar");
12565 if (rv_cmps != NIL && !has_union && !has_difference) {
12566 prov_atts = list_concat(prov_atts, rv_cmps);
12575 constants, q, prov_atts,
12581 foreach (lc_sort, q->sortClause) {
12582 SortGroupClause *sort = (SortGroupClause *)lfirst(lc_sort);
12584 foreach (lc_te, q->targetList) {
12585 TargetEntry *te = (TargetEntry *)lfirst(lc_te);
12586 if (sort->tleSortGroupRef == te->ressortgroupref) {
12588 provsql_error(
"ORDER BY on the result of an aggregate function is "
12601 constants, q, prov_atts, q->hasAggs, group_by_rewrite,
12603 nbcols, wrap_root, in_boolean_rewrite, inv_cert);
12608 if (rv_cmps != NIL) {
12609 FuncExpr *times = makeNode(FuncExpr);
12610 ArrayExpr *array = makeNode(ArrayExpr);
12613 times->funcvariadic =
true;
12614 times->location = -1;
12617 array->elements = lcons(
provenance, rv_cmps);
12618 array->location = -1;
12619 times->args = list_make1(array);
12632 foreach (lc_ev, given_evidence)
12639 if (has_difference)
12646 for (i = 0; columns != NULL && i < (unsigned)columns_len; ++i) {
12653 elog_node_display(NOTICE,
"ProvSQL: After query rewriting", q,
true);
12674 Index src_rteid = 0;
12675 RangeTblEntry *src_rte = NULL;
12676 RangeTblEntry *tgt_rte;
12677 AttrNumber provsql_attno = 0;
12678 TargetEntry *provsql_te = NULL;
12679 bool provsql_te_is_new =
false;
12682 foreach (lc, q->rtable) {
12683 RangeTblEntry *r = (RangeTblEntry *)lfirst(lc);
12685 if (r->rtekind == RTE_SUBQUERY && r->subquery &&
12692 if (src_rte == NULL)
12702 bool *removed = NULL;
12703 Query *new_subquery =
12704 process_query(constants, src_rte->subquery, &removed,
false,
false,
false,
12706 if (new_subquery == NULL)
12708 src_rte->subquery = new_subquery;
12712 tgt_rte = list_nth_node(RangeTblEntry, q->rtable, q->resultRelation - 1);
12713 if (tgt_rte->rtekind == RTE_RELATION) {
12714 AttrNumber attid = 1;
12715 foreach (lc, tgt_rte->eref->colnames) {
12717 get_atttype(tgt_rte->relid, attid) == constants->
OID_TYPE_UUID)
12718 provsql_attno = attid;
12723 if (provsql_attno == 0) {
12730 "tables: source provenance is not propagated "
12731 "to inserted rows");
12736 foreach (lc, q->targetList) {
12737 TargetEntry *te = (TargetEntry *)lfirst(lc);
12738 if (te->resno == provsql_attno &&
12745 if (provsql_te == NULL) {
12750 provsql_te = makeNode(TargetEntry);
12751 provsql_te->resno = provsql_attno;
12753 provsql_te_is_new =
true;
12758 AttrNumber src_provsql_attno = 0;
12760 foreach (lc, src_rte->subquery->targetList) {
12761 TargetEntry *te = (TargetEntry *)lfirst(lc);
12764 src_provsql_attno = te->resno;
12769 if (src_provsql_attno == 0)
12774 Var *v = makeNode(Var);
12775 v->varno = src_rteid;
12776 v->varattno = src_provsql_attno;
12779 v->varcollid = InvalidOid;
12781 provsql_te->expr = (Expr *)v;
12786 if (provsql_te_is_new)
12787 q->targetList = lappend(q->targetList, provsql_te);
12790 src_rte->eref->colnames = lappend(src_rte->eref->colnames,
12820 if (IsA(node, Query)) {
12821 Query *q = (Query *)node;
12823 foreach (lc, q->targetList) {
12824 TargetEntry *te = (TargetEntry *)lfirst(lc);
12825 if (te->resjunk || te->resname == NULL ||
12828 if (IsA(te->expr, Var) &&
12864#
if PG_VERSION_NUM >= 130000
12865 const char *query_string,
12868 ParamListInfo boundParams) {
12874 if (q->commandType == CMD_INSERT && q->rtable &&
provsql_active) {
12876 if (constants.
ok) {
12878 provsql_error(
"a subquery over a provenance-tracked relation cannot be "
12879 "used as a scalar subquery / IN / EXISTS expression; put "
12880 "it in the FROM clause instead");
12883 }
else if (q->commandType == CMD_SELECT) {
12898 provsql_error(
"a subquery over a provenance-tracked relation cannot be "
12899 "used as a scalar subquery / IN / EXISTS expression; put "
12900 "it in the FROM clause instead");
12913 && q->rtable != NIL) {
12921 bool *removed = NULL;
12932 provsql_error(
"a query may not define a column named \"%s\" by hand; "
12933 "ProvSQL manages the provenance column itself",
12936#if PG_VERSION_NUM >= 150000
12939 pg_get_querydef(q,
true));
12945 new_query =
process_query(&constants, q, &removed,
false,
true,
false,
12950 (
double)(clock() - begin) / CLOCKS_PER_SEC);
12952 if (new_query != NULL)
12955#if PG_VERSION_NUM >= 150000
12958 pg_get_querydef(q,
true));
12967#
if PG_VERSION_NUM >= 130000
12970 cursorOptions, boundParams);
12972 return standard_planner(q,
12973#
if PG_VERSION_NUM >= 130000
12976 cursorOptions, boundParams);
12997 standard_ExecutorStart(queryDesc, eflags);
13008#if PG_VERSION_NUM >= 130000
13014 standard_ExecutorEnd(queryDesc);
13030 standard_ExecutorEnd(queryDesc);
13099 CreateTableAsStmt *stmt;
13103 AttrNumber prov_resno = InvalidAttrNumber;
13104 Oid source_relid = InvalidOid;
13106 Bitmapset *ancestor_bms = NULL;
13113 if (parsetree == NULL || !IsA(parsetree, CreateTableAsStmt))
13115 stmt = (CreateTableAsStmt *) parsetree;
13116 if (stmt->query == NULL || !IsA(stmt->query, Query))
13118 qry = (Query *) stmt->query;
13119 if (qry->commandType != CMD_SELECT)
13132 foreach (lc, qry->targetList) {
13133 TargetEntry *te = (TargetEntry *) lfirst(lc);
13134 Node *e = (Node *) te->expr;
13136 RangeTblEntry *rte;
13137 AttrNumber prov_attno;
13141 while (e != NULL && IsA(e, RelabelType))
13142 e = (Node *) ((RelabelType *) e)->arg;
13143 if (e == NULL || !IsA(e, Var))
13146 if (v->varlevelsup != 0)
13148 if (v->varno < 1 || (
int) v->varno > list_length(qry->rtable))
13150 rte = (RangeTblEntry *) list_nth(qry->rtable, v->varno - 1);
13151 if (rte->rtekind != RTE_RELATION)
13154 if (prov_attno == InvalidAttrNumber || v->varattno != prov_attno)
13160 prov_resno = te->resno;
13161 source_relid = rte->relid;
13164 if (prov_resno == InvalidAttrNumber) {
13175 Oid src_relid = lfirst_oid(lc);
13179 for (uint16 i = 0; i < src_n; ++i)
13180 ancestor_bms = bms_add_member(ancestor_bms, (
int) src_ancestors[i]);
13182 ancestor_bms = bms_add_member(ancestor_bms, (
int) src_relid);
13189 while ((bms_member = bms_next_member(ancestor_bms, bms_member)) >= 0) {
13194 bms_free(ancestor_bms);
13197 cap->
ancestors[ancestor_n++] = (Oid) bms_member;
13199 bms_free(ancestor_bms);
13242 CreateTableAsStmt *stmt;
13244 AttrNumber prov_attno;
13246 uint16 eff_block_key_n = 0;
13249 Datum block_key_datum;
13250 Datum ancestors_datum;
13251 Datum *block_key_elems;
13252 Datum *ancestor_elems;
13253 ArrayType *block_key_arr;
13254 ArrayType *ancestors_arr;
13255 const char *nspname;
13256 const char *relname;
13257 StringInfoData trigger_sql;
13261 stmt = (CreateTableAsStmt *) parsetree;
13263 new_relid = RangeVarGetRelid(stmt->into->rel, NoLock,
true);
13264 if (new_relid == InvalidOid)
13272 if (prov_attno == InvalidAttrNumber)
13274 if (get_atttype(new_relid, prov_attno) != UUIDOID)
13289 bool found =
false;
13291 TargetEntry *te = (TargetEntry *) lfirst(lc);
13292 Node *e = (Node *) te->expr;
13294 RangeTblEntry *rte;
13297 while (e != NULL && IsA(e, RelabelType))
13298 e = (Node *) ((RelabelType *) e)->arg;
13299 if (e == NULL || !IsA(e, Var))
13302 if (v->varlevelsup != 0)
13305 || (
int) v->varno > list_length(cap->
inner_query->rtable))
13307 rte = (RangeTblEntry *)
13308 list_nth(cap->
inner_query->rtable, v->varno - 1);
13309 if (rte->rtekind != RTE_RELATION)
13312 && v->varattno == src_attno) {
13317 eff_block_key[eff_block_key_n++] = te->resno;
13329 eff_block_key_n = 0;
13338 if (eff_block_key_n == 0) {
13339 block_key_arr = construct_empty_array(INT2OID);
13341 block_key_elems = palloc(eff_block_key_n *
sizeof(Datum));
13342 for (uint16 i = 0; i < eff_block_key_n; ++i)
13343 block_key_elems[i] = Int16GetDatum(eff_block_key[i]);
13344 block_key_arr = construct_array(block_key_elems, eff_block_key_n,
13345 INT2OID, 2,
true,
's');
13346 pfree(block_key_elems);
13348 block_key_datum = PointerGetDatum(block_key_arr);
13350 ObjectIdGetDatum(new_relid),
13355 ancestors_arr = construct_empty_array(OIDOID);
13357 ancestor_elems = palloc(cap->
ancestor_n *
sizeof(Datum));
13358 for (uint16 i = 0; i < cap->
ancestor_n; ++i)
13359 ancestor_elems[i] = ObjectIdGetDatum(cap->
ancestors[i]);
13360 ancestors_arr = construct_array(ancestor_elems, cap->
ancestor_n,
13361 OIDOID,
sizeof(Oid),
true,
'i');
13362 pfree(ancestor_elems);
13364 ancestors_datum = PointerGetDatum(ancestors_arr);
13366 ObjectIdGetDatum(new_relid),
13383#if PG_VERSION_NUM >= 140000
13384 if (stmt->objtype == OBJECT_MATVIEW)
13386 if (stmt->relkind == OBJECT_MATVIEW)
13390 nspname = get_namespace_name(get_rel_namespace(new_relid));
13391 relname = get_rel_name(new_relid);
13392 if (nspname == NULL || relname == NULL)
13394 initStringInfo(&trigger_sql);
13395 appendStringInfo(&trigger_sql,
13396 "CREATE TRIGGER provenance_guard "
13397 "BEFORE INSERT OR UPDATE OF provsql ON %s.%s "
13402 "FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()",
13403 quote_identifier(nspname), quote_identifier(relname));
13404 if (SPI_connect() != SPI_OK_CONNECT)
13406 if (SPI_exec(trigger_sql.data, 0) != SPI_OK_UTILITY)
13407 provsql_error(
"CTAS lineage hook: failed to install provenance_guard "
13408 "on %s.%s", nspname, relname);
13410 pfree(trigger_sql.data);
13414 PlannedStmt *pstmt,
13415 const char *queryString,
13416#
if PG_VERSION_NUM >= 140000
13419 ProcessUtilityContext context,
13420 ParamListInfo params,
13421 QueryEnvironment *queryEnv,
13422 DestReceiver *dest,
13423#
if PG_VERSION_NUM >= 130000
13424 QueryCompletion *qc
13426 char *completionTag
13429 Node *parsetree = pstmt ? pstmt->utilityStmt : NULL;
13436#
if PG_VERSION_NUM >= 140000
13439 context, params, queryEnv, dest,
13440#
if PG_VERSION_NUM >= 130000
13447 standard_ProcessUtility(pstmt, queryString,
13448#
if PG_VERSION_NUM >= 140000
13451 context, params, queryEnv, dest,
13452#
if PG_VERSION_NUM >= 130000
13473#ifndef PROVSQL_INPROCESS_STORE
13481 if (!process_shared_preload_libraries_in_progress)
13482 provsql_error(
"provsql needs to be added to the shared_preload_libraries "
13483 "configuration variable");
13486 DefineCustomBoolVariable(
"provsql.active",
13487 "Should ProvSQL track provenance?",
13488 "1 is standard ProvSQL behavior, 0 means provsql attributes will be dropped.",
13496 DefineCustomEnumVariable(
"provsql.provenance",
13497 "Provenance class tracked and assumed by the rewriter.",
13498 "Declares, for the session, the most specific "
13499 "class of provenance semantics the circuits "
13500 "must remain faithful for; constructions are "
13501 "licensed accordingly, from the most general "
13502 "to the most specialised: 'where' adds "
13503 "where-provenance tracking (equality and "
13504 "projection gates) on top of universal "
13505 "semiring provenance; 'semiring' (the "
13506 "default) tracks universal semiring "
13507 "provenance; 'absorptive' additionally lets "
13508 "recursive queries on cyclic data stop at "
13509 "the absorptive value fixpoint, tagging "
13510 "their tokens so non-absorptive semirings "
13511 "refuse them; 'boolean' (which implies "
13512 "'absorptive') additionally enables the "
13513 "Boolean-only machinery -- the safe-query "
13514 "read-once rewrite, the bounded-treewidth "
13515 "reachability route, Boolean circuit "
13516 "simplifications -- whose outputs only "
13517 "preserve the Boolean function of the "
13518 "lineage and are tagged as such.",
13527 DefineCustomBoolVariable(
"provsql.update_provenance",
13528 "Should ProvSQL track update provenance?",
13529 "1 turns update provenance on, 0 off.",
13537 DefineCustomBoolVariable(
"provsql.aggtoken_text_as_uuid",
13538 "Output agg_token cells as the underlying UUID "
13539 "instead of \"value (*)\".",
13540 "Off by default for psql-friendly output. UI "
13541 "layers (notably ProvSQL Studio) flip this on "
13542 "per session so aggregate cells expose the "
13543 "circuit root UUID for click-through; the "
13544 "display value is recovered via "
13545 "provsql.agg_token_value_text(uuid).",
13553 DefineCustomIntVariable(
"provsql.verbose_level",
13554 "Level of verbosity for ProvSQL informational and debug messages",
13555 "0 for quiet (default), 1-9 for informational messages, 10-100 for debug information.",
13565 DefineCustomStringVariable(
"provsql.tool_search_path",
13566 "Directories prepended to PATH when ProvSQL spawns external tools (superuser-only).",
13567 "Colon-separated list of directories searched before the server's PATH "
13568 "when locating d4, c2d, minic2d, dsharp, weightmc, or graph-easy. "
13569 "Empty (default) means rely on the server's PATH alone. "
13570 "Restricted to superusers (PGC_SUSET): it controls which directories the "
13571 "postgres OS user searches for executables, so a non-privileged role must "
13572 "not be able to redirect it to an attacker-controlled binary.",
13580 DefineCustomStringVariable(
"provsql.fallback_compiler",
13581 "Compiler used by makeDD's final fallback when both "
13582 "interpretAsDD and tree-decomposition fail.",
13583 "Name of the external compiler invoked by "
13584 "BooleanCircuit::makeDD after interpretAsDD raises "
13585 "(non-independent or non-NNF circuit) and the "
13586 "tree-decomposition builder raises (treewidth above "
13587 "the supported bound). Accepts any value supported "
13588 "by BooleanCircuit::compilation: d4, d4v2, c2d, "
13589 "minic2d, dsharp, panini-obdd, panini-obdd-and, "
13590 "panini-decdnnf. Default: d4.",
13598 DefineCustomStringVariable(
"provsql.kcmcp_server",
13599 "Launch command for the managed KCMCP knowledge-compiler server.",
13600 "Shell command the supervisor background worker runs to start a "
13601 "warm KCMCP server (see the KC server protocol). The literal "
13602 "{endpoint} is replaced by a Unix-socket path the worker picks "
13603 "and publishes for the in-extension client to reach (a registry "
13604 "record of kind 'kcmcp' with endpoint 'managed' uses it). {endpoint} "
13605 "already carries the scheme (e.g. unix:/path). Empty (default) "
13606 "launches no server. Example: 'tdkc --kcmcp {endpoint}'. "
13607 "PGC_SIGHUP (config file / ALTER SYSTEM + reload): it runs an "
13608 "arbitrary command as the postgres OS user, so like "
13609 "provsql.tool_search_path it is not settable per session.",
13617 DefineCustomStringVariable(
"provsql.last_eval_method",
13618 "Probability evaluation method(s) used by the most "
13619 "recent probability_evaluate call.",
13620 "Set automatically after each probability_evaluate "
13621 "call to the method that produced the result "
13622 "(comma-separated and deduplicated across calls in "
13623 "the session). Useful to see which strategy the "
13624 "default auto-selection settled on.",
13632 DefineCustomBoolVariable(
"provsql.simplify_on_load",
13633 "Apply universal cmp-resolution passes when "
13634 "loading a provenance circuit.",
13635 "When on (default), every GenericCircuit returned "
13636 "by getGenericCircuit goes through RangeCheck "
13637 "(and any future universal pass): comparators "
13638 "decidable to certain Boolean values become "
13639 "Bernoulli gate_input gates with probability 0 "
13640 "or 1, transparent to every downstream consumer "
13641 "(semiring evaluators, MC, view_circuit, PROV "
13642 "export). Set off to inspect raw circuit "
13643 "structure (e.g. when debugging gate-creation "
13657 DefineCustomBoolVariable(
"provsql.hybrid_evaluation",
13658 "Run the hybrid-evaluator simplifier and "
13659 "island decomposer inside probability_evaluate. "
13661 "When on (default), probability_evaluate runs "
13662 "the HybridEvaluator peephole simplifier "
13663 "between RangeCheck and AnalyticEvaluator and "
13664 "the per-cmp MC island decomposer after "
13665 "AnalyticEvaluator. Off bypasses both and lets "
13666 "unresolved comparators fall through to "
13667 "whole-circuit MC. End users have no reason "
13668 "to flip this; it exists for developer A/B "
13669 "testing against the unfolded path and as a "
13670 "bisection knob if a closure rule turns out "
13671 "to be unsound on some workload.",
13675 GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE,
13688 DefineCustomBoolVariable(
"provsql.cmp_probability_evaluation",
13689 "Run closed-form / analytic probability "
13690 "evaluators for gate_cmps inside "
13691 "probability_evaluate. Debug only.",
13692 "When on (default), probability_evaluate "
13693 "runs pre-passes that recognise specific "
13694 "gate_cmp shapes (currently HAVING COUNT(*) "
13695 "op C over distinct gate_input leaves) and "
13696 "replace each cmp with a Bernoulli "
13697 "gate_input carrying the closed-form "
13698 "probability, bypassing the DNF that "
13699 "provsql_having's enumerate_valid_worlds "
13700 "would otherwise emit. Off forces the cmp "
13701 "to fall through to that enumeration path. "
13702 "Future MIN / MAX / SUM probability "
13703 "evaluators will gate on the same flag. "
13704 "End users have no reason to flip this; it "
13705 "exists for developer A/B testing and as a "
13706 "bisection escape valve.",
13710 GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE,
13720 DefineCustomBoolVariable(
"provsql.inversion_free",
13721 "Use the inversion-free structured-d-DNNF "
13722 "probability path when available.",
13723 "When on (default), probability_evaluate, on a "
13724 "query whose provenance root carries an "
13725 "inversion-free tractability certificate, tries the "
13726 "structured-d-DNNF builder after the read-once "
13727 "independent evaluator and before the "
13728 "tree-decomposition / external-compiler fallback. "
13729 "Off disables only this automatic insertion; the "
13730 "explicit probability_evaluate(token, "
13731 "'inversion-free') method always runs and errors "
13732 "without a certificate. The path is gated on the "
13733 "certificate, attached only to certified queries, "
13734 "so on is safe; off serves developer A/B testing.",
13738 GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE,
13742 DefineCustomBoolVariable(
"provsql.classify_top_level",
13743 "Emit a NOTICE classifying each top-level SELECT.",
13744 "When on, every top-level SELECT that "
13745 "touches a relation triggers a NOTICE of "
13746 "the form `ProvSQL: query result is "
13747 "<KIND> (sources: ...)` where <KIND> is "
13748 "TID, BID, or OPAQUE under the existing "
13749 "provsql_table_kind taxonomy and the "
13750 "sources list names the provenance-"
13751 "tracked base relations the query touches. "
13752 "Read-only : the classifier does not "
13753 "rewrite the query. Studio reads the "
13754 "NOTICE to label query results with their "
13763 DefineCustomIntVariable(
"provsql.monte_carlo_seed",
13764 "Seed for the Monte Carlo sampler.",
13765 "-1 (default) seeds from std::random_device for "
13766 "non-deterministic sampling. Any other value "
13767 "(including 0) is used as a literal seed for "
13768 "std::mt19937_64, making "
13769 "probability_evaluate(..., 'monte-carlo', n) "
13770 "reproducible across runs and across the Bernoulli "
13771 "and continuous (gate_rv) sampling paths.",
13781 DefineCustomIntVariable(
"provsql.rv_mc_samples",
13782 "Default sample count for analytical-evaluator MC fallbacks.",
13783 "Used when an analytical evaluator (Expectation, "
13784 "future hybrid evaluator, etc.) cannot decompose a "
13785 "sub-circuit and needs to fall back to Monte Carlo. "
13786 "Default 10000. Set to 0 to disable the fallback "
13787 "entirely: callers raise an exception rather than "
13788 "sampling, which is useful when only analytical "
13789 "answers are acceptable. Unrelated to "
13790 "probability_evaluate(..., 'monte-carlo', n) where "
13791 "the sample count is an explicit argument.",
13802 DefineCustomIntVariable(
"provsql.dtree_max_subproblems",
13803 "Hard cap on d-tree subproblems before it bails (0 = off).",
13804 "Debug / safety knob for the d-tree speculative-execution "
13805 "budget. The cost chooser already budgets the d-tree at the "
13806 "next-best method's estimated cost; when this is > 0 it adds "
13807 "a fixed hard cap on the number of d-tree subproblems, after "
13808 "which the method throws and the chooser escalates to the "
13809 "next method. 0 leaves only the automatic budget.",
13820 DefineCustomIntVariable(
"provsql.joint_max_treewidth",
13821 "Maximum joint treewidth the joint-width UCQ "
13822 "compiler attempts.",
13823 "The joint-width UCQ compiler "
13824 "(ucq_joint_evaluate) evaluates an arbitrary UCQ -- "
13825 "including queries that are #P-hard under the "
13826 "Dalvi-Suciu dichotomy -- exactly, tractably when "
13827 "the joint treewidth of the data and its "
13828 "correlation structure is bounded. Above this "
13829 "bound the path declines (the degeneracy screen or "
13830 "the min-fill build raises), and the caller falls "
13831 "back to the standard probability ladder. Default "
13832 "10 (the tree-decomposition compiler's own cap).",
13842 DefineCustomIntVariable(
"provsql.joint_max_states",
13843 "Per-bag DP state-count cap of the joint-width UCQ "
13845 "The joint-width UCQ compiler caps the number of "
13846 "dynamic-programming states at any decomposition "
13847 "node; exceeding it raises and the caller falls "
13848 "back to the ladder. This cap, not the static "
13849 "enumerating-variable count, is the true safety "
13850 "net: the realised state count is governed by data "
13851 "sparsity and the absorbing satisfied-state "
13852 "collapse, typically far below the a-priori bound. "
13864 DefineCustomBoolVariable(
"provsql.joint_width",
13865 "Recognise unsafe UCQs at planner time and route "
13866 "their existence provenance through the "
13867 "joint-width compiler (debug-only switch).",
13868 "On by default. When provsql.provenance = "
13869 "'boolean', a conjunctive query the safe-query "
13870 "rewriter declined -- an unsafe / #P-hard UCQ -- "
13871 "whose existence is being formed (DISTINCT / GROUP "
13872 "BY) is recognised and its provenance replaced by "
13873 "the joint-width compiler's certified d-D (exact "
13874 "and tractable when the joint treewidth of the data "
13875 "and its correlation structure is bounded). Turn "
13876 "off only to compare against the general lineage "
13886 DefineCustomBoolVariable(
"provsql.mobius",
13887 "Try the safe-UCQ Möbius-inversion route before the "
13888 "joint-width compiler (debug-only switch).",
13889 "On by default. The last missing exact route of the "
13890 "Dalvi-Suciu dichotomy: a UCQ safe only because the "
13891 "#P-hard terms of its inclusion-exclusion expansion "
13892 "carry a zero Möbius value on the CNF lattice and "
13893 "cancel (canonical witness QW / q9). Shares the "
13894 "joint-width descriptor but has PRECEDENCE over it: a "
13895 "guaranteed-PTIME exact route for its class (TID, "
13896 "self-join-free, safe), it is tried first and "
13897 "short-circuits past the joint-width compiler on "
13898 "success. The joint-width compiler runs only on a "
13899 "Möbius decline (correlated inputs, self-joins, "
13900 "unsafe shape); on its decline too the normal "
13901 "provenance is the fallback, so the query never "
13902 "fails. Turn off only to compare against the "
13903 "joint-width / general lineage for debugging.",
13912 DefineCustomIntVariable(
"provsql.mobius_max_gates",
13913 "Data-cost cap of the safe-UCQ Möbius-inversion "
13915 "The Möbius route is PTIME in its class but its "
13916 "lifted-inference recursion is O(|D|^k) in the data, "
13917 "k the safe query's level (number of nested "
13918 "independent-projections) -- supra-linear, and the "
13919 "degree grows with the query. To keep it safe to "
13920 "leave on by default with precedence, it declines "
13921 "(falling through to the joint-width compiler / the "
13922 "ladder) once its compile has built more than this "
13923 "many gates, so a high-level safe query on large data "
13924 "never out-costs the general pipeline. Default "
13937 EmitWarningsOnPlaceholders(
"provsql");
13944#ifdef PROVSQL_INPROCESS_STORE
13948 provsql_inproc_init();
13949#elif (PG_VERSION_NUM >= 150000)
13957#ifndef PROVSQL_INPROCESS_STORE
13964#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_SUM_INT4
OID of sum(int4) aggregate function (pre-PG 14).
#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).
#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 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 qual_class classify_qual(Expr *expr, const constants_t *constants)
Classify expr along the qual_class axis.
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 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 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 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 Query * lookup_lowered_cte(List *lowered, const char *name)
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 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 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 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)
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 oj_limit_count_is_one(Node *limitCount)
Is limitCount the literal 1?
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 ...
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_param_repl_mut(Node *node, void *cx)
Replace every PARAM_SUBLINK with paramid by replacement.
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.
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 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 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 provsql_executor_start(QueryDesc *queryDesc, int eflags)
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.
static void inline_ctes(Query *q)
Inline all CTE references in q as subqueries.
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 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 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 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 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)
Rewrite a single SELECT query to carry provenance.
static Query * rewrite_agg_distinct(Query *q, const constants_t *constants)
Rewrite every AGG(DISTINCT key) in q using independent subqueries.
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.
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 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 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 List * get_provenance_attributes(const constants_t *constants, Query *q, bool in_boolean_rewrite, const InvFreeMarkerCtx *inv_ctx)
Collect all provenance Var nodes reachable from q's range table.
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 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 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 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 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 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 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.
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 a single tracked relation int...
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 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 void inline_ctes_in_rtable(List *rtable, List *cteList, List **lowered)
Inline CTE references as subqueries within a query.
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 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 into the same aggregate over provenance-wrapped per-row a...
static void error_for_mixed_qual(qual_class c)
Raise the user-facing error appropriate to a mixed c.
static Node * extract_quantified_corr(SubLink *sl, bool *antijoin)
Build the per-row correlation for a quantified sublink (IN / op ANY / op ALL), setting *antijoin.
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 FlatAtomOrigin * flat_origin_prepend(int slot, const FlatAtomOrigin *sub)
Prepend slot to sub's path, for an atom inlined one level up.
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...
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 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_CHOOSE
OID of the choose(anyelement) aggregate (keeps the first non-NULL value); used to decorrelate scalar ...
Oid OID_FUNCTION_ANNOTATE
OID of provsql.annotate(uuid,text)->uuid.
Oid OID_FUNCTION_PROVENANCE
OID of the provenance FUNCTION.
Oid OID_FUNCTION_INVERSION_FREE_KEY
OID of provsql.inversion_free_key(text,text,int)->text.
Oid OID_FUNCTION_AGG_TOKEN_UUID
OID of the agg_token_uuid FUNCTION.
Oid OID_FUNCTION_RV_AGGREGATE_SEMIMOD
OID of rv_aggregate_semimod helper (uuid, rv -> rv) used to wrap each per-row argument of an RV-retur...
Oid OID_FUNCTION_GATE_ZERO
OID of the provenance_zero FUNCTION.
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_GET_CHILDREN
OID of the get_children FUNCTION.
Oid OID_UNNEST
OID of the unnest(anyarray) FUNCTION.
Oid OID_FUNCTION_COND_PREDICATE
cond_predicate(uuid,boolean)
Oid OID_TYPE_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_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_GIVEN
OID of provsql.given(uuid)->uuid.
Oid OID_FUNCTION_GATE_ONE
OID of the provenance_one FUNCTION.
Oid OID_FUNCTION_RV_COND
OID of provsql.random_variable_cond(random_variable,uuid).
Oid OID_FUNCTION_RV_COND_PREDICATE
random_variable_cond_predicate(random_variable,boolean)
Oid OID_TYPE_UUID_ARRAY
OID of the uuid[] TYPE.
Oid OID_FUNCTION_AGG_COND
OID of provsql.agg_token_cond(agg_token,uuid): the conditioning constructor for the agg_token carrier...
Oid OID_TYPE_RANDOM_VARIABLE
OID of the random_variable TYPE.
Oid OID_FUNCTION_PROVENANCE_CMP
OID of the provenance_cmp FUNCTION.
Oid OID_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...
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).
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].
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 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.
Context for sublink_classify_walker.
const constants_t * constants
bool has_unsupported_direct
Context for sublink_over_tracked_walker.
const constants_t * constants