513 Query *q, Node *quals,
516 List *eq_pairs = NIL;
521 int natoms = list_length(q->rtable);
522 int *class_atom_count;
523 int *class_atom_anchor_attno;
525 List *atoms_out = NIL;
526 int *atom_group = NULL;
527 bool *in_targetlist = NULL;
528 int *first_member_of_group = NULL;
529 int *group_singleton_counter = NULL;
530 bool have_partial_class =
false;
531 int partial_first = -1;
532 Bitmapset *bridging_classes = NULL;
546 bool *determined_in = NULL;
547 int *class_atom_count_fd = NULL;
548 bool fd_aware_mode =
false;
549 int *atom_anchor_class = NULL;
567 expression_tree_walker((Node *) q->targetList,
572 nvars = list_length(vctx.
vars);
576 vars_arr = palloc(nvars *
sizeof(Var *));
577 cls = palloc(nvars *
sizeof(
int));
579 foreach (lc, vctx.
vars) {
580 vars_arr[i] = (Var *) lfirst(lc);
593 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
595 int li, ri, ci, cj, k;
596 lv = (Var *) lfirst(lc);
598 rv = (Var *) lfirst(lc);
601 if (li < 0 || ri < 0)
607 for (k = 0; k < nvars; k++)
614 class_atom_count = palloc0(nvars *
sizeof(
int));
615 class_atom_anchor_attno =
616 palloc0((
size_t) nvars * (
size_t) natoms *
sizeof(
int));
618#define ANCHOR(c, atom_idx) class_atom_anchor_attno[(c) * natoms + (atom_idx)]
620 for (i = 0; i < nvars; i++) {
623 varno = vars_arr[i]->varno;
624 if (varno < 1 || (
int) varno > natoms)
626 atom_idx = (int) varno - 1;
627 if (
ANCHOR(c, atom_idx) == 0) {
628 class_atom_count[c]++;
629 ANCHOR(c, atom_idx) = vars_arr[i]->varattno;
630 }
else if (
ANCHOR(c, atom_idx) != vars_arr[i]->varattno) {
635 class_atom_count[c] = natoms + 1;
660 palloc0((
size_t) nvars * (
size_t) natoms *
sizeof(
bool));
661#define DETERMINED(c, atom_idx) determined_in[(c) * natoms + (atom_idx)]
663 for (j = 0; j < natoms; j++) {
664 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
667 if (rte->rtekind != RTE_RELATION)
671 for (ki = 0; ki < keys.
key_n; ki++) {
673 bool all_anchored =
true;
686 for (kc = 0; kc < key->
col_n; kc++) {
691 all_anchored =
false;
694 if (class_atom_count[cls[idx]] < 2
695 || class_atom_count[cls[idx]] > natoms) {
696 all_anchored =
false;
704 for (vi = 0; vi < nvars; vi++) {
705 Var *vp = vars_arr[vi];
706 bool is_key_col =
false;
707 if (vp->varno != (Index) (j + 1))
709 for (kc = 0; kc < key->
col_n; kc++) {
710 if (vp->varattno == key->
cols[kc]) {
767 for (j = 0; j < natoms; j++) {
768 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
769 AttrNumber provsql_attno;
770 bool has_provsql_col;
773 Form_pg_class classform;
775 if (rte->rtekind != RTE_RELATION)
779 provsql_attno != InvalidAttrNumber
780 && get_atttype(rte->relid, provsql_attno) == constants->
OID_TYPE_UUID;
782 if (has_provsql_col || has_meta)
786 SearchSysCache1(RELOID, ObjectIdGetDatum(rte->relid));
787 if (!HeapTupleIsValid(class_tup))
789 classform = (Form_pg_class) GETSTRUCT(class_tup);
790 ok_relkind = (classform->relkind == RELKIND_RELATION);
791 ReleaseSysCache(class_tup);
795 if (has_superclass(rte->relid))
802 for (i = 0; i < nvars; i++) {
813 class_atom_count_fd = palloc0(nvars *
sizeof(
int));
814 for (i = 0; i < nvars; i++) {
818 if (class_atom_count[i] > natoms)
821 for (j = 0; j < natoms; j++) {
823 class_atom_count_fd[c]++;
832 in_targetlist = palloc0(nvars *
sizeof(
bool));
836 expression_tree_walker((Node *) q->targetList,
838 foreach (tlc, tlist_ctx.
vars) {
839 Var *v = (Var *) lfirst(tlc);
842 in_targetlist[idx] =
true;
849 for (i = 0; i < nvars; i++) {
852 if (class_atom_count[i] == natoms) {
889 if (root_class < 0 && determined_in != NULL) {
894 for (i = 0; i < nvars; i++) {
898 if (class_atom_count[c] >= 2 && class_atom_count[c] <= natoms) {
908 for (i = 0; i < nvars; i++)
909 if (in_targetlist[i]) { ok_fd =
false;
break; }
912 int ca = multi[0], cb = multi[1];
913 int ydet = -1, xdet = -1, satom = -1;
918 for (j = 0; j < natoms; j++) {
920 int yd = -1, xd = -1;
922 else if (
DETERMINED(cb, j)) { yd = cb; xd = ca; }
923 if (yd < 0) { ok_fd =
false;
break; }
924 if (ydet >= 0) { ok_fd =
false;
break; }
925 ydet = yd; xdet = xd; satom = j;
935 for (j = 0; j < natoms; j++) {
936 bool hx =
ANCHOR(xdet, j) != 0;
937 bool hy =
ANCHOR(ydet, j) != 0;
938 if (!hx && !hy) { ok_fd =
false;
break; }
939 if (hx && hy && j != satom){ ok_fd =
false;
break; }
958 for (j = 0; j < natoms; j++) {
960 bool hx =
ANCHOR(xdet, j) != 0;
972 if (
ANCHOR(ydet, j) != 0) {
987 atoms_out = lappend(atoms_out, sa);
989 *groups_out = list_make1(gr);
993 "fired (grouped %d-atom determining side on the "
997 pfree(class_atom_count);
998 pfree(class_atom_anchor_attno);
1001 if (in_targetlist) pfree(in_targetlist);
1002 if (determined_in) pfree(determined_in);
1003 if (class_atom_count_fd) pfree(class_atom_count_fd);
1047 if (root_class < 0) {
1048 bool eligible =
true;
1050 for (i = 0; i < nvars && eligible; i++) {
1053 if (class_atom_count[i] > natoms) {
1059 bool *atom_covered = palloc0(natoms *
sizeof(
bool));
1060 for (i = 0; i < nvars; i++) {
1062 Index vn = vars_arr[i]->varno;
1063 if (vn < 1 || (
int) vn > natoms)
1065 if (class_atom_count[c] > natoms)
1067 atom_covered[vn - 1] =
true;
1069 for (j = 0; j < natoms; j++) {
1070 if (!atom_covered[j]) {
1075 pfree(atom_covered);
1081 Bitmapset **atoms_fd = palloc0(nvars *
sizeof(Bitmapset *));
1082 int *class_reprs = palloc(nvars *
sizeof(
int));
1084 for (i = 0; i < nvars && eligible; i++) {
1087 if (class_atom_count[i] > natoms)
1089 if (class_atom_count[i] < 2)
1091 for (j = 0; j < natoms; j++) {
1093 atoms_fd[i] = bms_add_member(atoms_fd[i], j);
1095 class_reprs[nreprs++] = i;
1097 for (i = 0; i < nreprs && eligible; i++) {
1099 for (k = i + 1; k < nreprs && eligible; k++) {
1100 Bitmapset *a = atoms_fd[class_reprs[i]];
1101 Bitmapset *b = atoms_fd[class_reprs[k]];
1102 bool nested = bms_is_subset(a, b) || bms_is_subset(b, a);
1103 bool disjoint = !bms_overlap(a, b);
1104 if (!nested && !disjoint) {
1110 for (i = 0; i < nvars; i++)
1112 bms_free(atoms_fd[i]);
1134 atom_anchor_class = palloc(natoms *
sizeof(
int));
1135 for (j = 0; j < natoms; j++)
1136 atom_anchor_class[j] = -1;
1137 for (i = 0; i < nvars; i++) {
1141 if (class_atom_count[i] > natoms)
1143 if (class_atom_count[i] < 2)
1146 for (j = 0; j < natoms; j++) {
1148 && atom_anchor_class[j] < 0)
1149 atom_anchor_class[j] = c;
1152 for (j = 0; j < natoms; j++) {
1153 if (atom_anchor_class[j] >= 0)
1155 for (i = 0; i < nvars; i++) {
1158 if (class_atom_count[i] < 2 || class_atom_count[i] > natoms)
1161 atom_anchor_class[j] = i;
1170 for (j = 0; j < natoms; j++) {
1171 if (atom_anchor_class[j] < 0) {
1178 fd_aware_mode =
true;
1210 atom_group = palloc(natoms *
sizeof(
int));
1211 for (j = 0; j < natoms; j++)
1220 goto skip_partial_coverage;
1223 Bitmapset **sig = palloc0(natoms *
sizeof(Bitmapset *));
1224 bool has_outer_atom =
true;
1226 for (i = 0; i < nvars; i++) {
1230 if (class_atom_count[c] < 2)
1232 if (class_atom_count[c] > natoms)
1234 if (class_atom_count[c] == natoms)
1236 have_partial_class =
true;
1237 if (partial_first < 0)
1239 for (j = 0; j < natoms; j++) {
1241 sig[j] = bms_add_member(sig[j], c);
1245 if (have_partial_class) {
1246 has_outer_atom =
false;
1247 for (j = 0; j < natoms; j++) {
1248 if (bms_is_empty(sig[j])) {
1249 has_outer_atom =
true;
1255 if (have_partial_class && has_outer_atom) {
1258 for (j = 0; j < natoms; j++)
1259 atom_group[j] = bms_is_empty(sig[j]) ? -1 : 0;
1260 }
else if (have_partial_class) {
1274 Bitmapset **group_sigs;
1280 group_sigs = palloc0(natoms *
sizeof(Bitmapset *));
1281 for (j = 0; j < natoms; j++) {
1283 for (g = 0; g < ngroups; g++) {
1284 if (bms_equal(group_sigs[g], sig[j])) {
1291 atom_group[j] = ngroups;
1292 group_sigs[ngroups] = sig[j];
1300 for (i = 0; i < nvars; i++) {
1302 Bitmapset *touched_groups = NULL;
1306 if (class_atom_count[c] < 2 || class_atom_count[c] >= natoms)
1308 for (jj = 0; jj < natoms; jj++) {
1310 touched_groups = bms_add_member(touched_groups,
1313 if (bms_num_members(touched_groups) > 1)
1314 bridging_classes = bms_add_member(bridging_classes, c);
1315 bms_free(touched_groups);
1321 if (!bms_is_empty(bridging_classes)) {
1322 int *parent = palloc(ngroups *
sizeof(
int));
1323 int *super = palloc(ngroups *
sizeof(
int));
1327 for (g = 0; g < ngroups; g++) {
1333 while ((c = bms_next_member(bridging_classes, c)) >= 0) {
1336 for (jj = 0; jj < natoms; jj++) {
1340 gj = atom_group[jj];
1347 while (parent[ra] != ra) ra = parent[ra];
1349 while (parent[rb] != rb) rb = parent[rb];
1355 for (g = 0; g < ngroups; g++) {
1357 while (parent[r] != r) r = parent[r];
1359 super[r] = next_super++;
1360 super[g] = super[r];
1363 for (j = 0; j < natoms; j++) {
1364 if (atom_group[j] >= 0)
1365 atom_group[j] = super[atom_group[j]];
1370 bms_free(bridging_classes);
1371 bridging_classes = NULL;
1375 for (j = 0; j < natoms; j++) bms_free(sig[j]);
1379skip_partial_coverage:
1390 int g, ngroups_local = 0;
1391 for (j = 0; j < natoms; j++)
1392 if (atom_group[j] >= 0 && atom_group[j] + 1 > ngroups_local)
1393 ngroups_local = atom_group[j] + 1;
1394 first_member_of_group = palloc(natoms *
sizeof(
int));
1395 group_singleton_counter = palloc(natoms *
sizeof(
int));
1396 for (g = 0; g < ngroups_local; g++) {
1397 first_member_of_group[g] = -1;
1398 group_singleton_counter[g] = 0;
1400 for (j = 0; j < natoms; j++) {
1401 int g_loc = atom_group[j];
1402 if (g_loc >= 0 && first_member_of_group[g_loc] < 0)
1403 first_member_of_group[g_loc] = j;
1422 for (i = 0; i < nvars; i++) {
1424 int atom_idx = (int) vars_arr[i]->varno - 1;
1425 if (fd_aware_mode) {
1426 if (class_atom_count[c] >= 2 && class_atom_count[c] <= natoms)
1428 if (class_atom_count[c] == 1 && in_targetlist[i])
1431 provsql_notice(
"safe-query rewriter (fd-aware): Var (varno=%u, varattno=%d) "
1432 "belongs to a class with no outer slot",
1433 (
unsigned) vars_arr[i]->varno,
1434 (
int) vars_arr[i]->varattno);
1438 if (class_atom_count[c] == natoms)
1440 if (class_atom_count[c] >= 2 && class_atom_count[c] < natoms
1441 && atom_group[atom_idx] >= 0)
1450 if (class_atom_count[c] == 1 && in_targetlist[i])
1453 provsql_notice(
"safe-query rewriter: Var (varno=%u, varattno=%d) "
1454 "belongs to a class that does not match any outer or "
1455 "inner-group slot -- rewrite scope does not yet cover "
1457 (
unsigned) vars_arr[i]->varno,
1458 (
int) vars_arr[i]->varattno);
1477 for (j = 0; j < natoms; j++) {
1480 int local_root = fd_aware_mode ? atom_anchor_class[j] : root_class;
1482 sa->
rtindex = (Index) (j + 1);
1498 for (i = 0; i < nvars; i++) {
1500 if (cls[i] != i || i == local_root)
1502 if (fd_aware_mode) {
1508 if (class_atom_count[i] < 2 || class_atom_count[i] > natoms)
1510 }
else if (class_atom_count[i] != natoms) {
1531 for (i = 0; i < nvars; i++) {
1534 bool already_have =
false;
1535 bool is_first_member;
1536 if (!in_targetlist[i])
1538 if (class_atom_count[cls[i]] != 1)
1540 if ((
int) vars_arr[i]->varno - 1 != j)
1544 if (ex->
base_attno == vars_arr[i]->varattno) {
1545 already_have =
true;
1554 is_first_member = (sa->
group_id >= 0
1555 && first_member_of_group[sa->
group_id] == j);
1556 if (sa->
group_id < 0 || is_first_member) {
1558 (AttrNumber) (list_length(sa->
proj_slots) + 1);
1560 group_singleton_counter[sa->
group_id]++;
1562 (AttrNumber) group_singleton_counter[sa->
group_id];
1570 && first_member_of_group[sa->
group_id] == j) {
1571 group_singleton_counter[sa->
group_id] =
1586 RangeTblEntry *rte =
1587 (RangeTblEntry *) list_nth(q->rtable, j);
1594 "has an empty block_key (whole table is one "
1595 "block); the wrap's DISTINCT could split the "
1596 "block across multiple output rows, deferred",
1615 "has block_key column attno=%d outside the "
1616 "projection slots; the wrap would split a "
1626 atoms_out = lappend(atoms_out, sa);
1635 if (have_partial_class) {
1640 foreach (alc, atoms_out) {
1646 for (g = 0; g <= max_gid; g++) {
1653 foreach (alc, atoms_out) {
1675 for (g = 0; g <= max_gid; g++) {
1676 for (i = 0; i < nvars; i++) {
1679 AttrNumber first_attno = 0;
1680 Oid first_type = InvalidOid;
1681 int32 first_typmod = -1;
1682 Oid first_coll = InvalidOid;
1686 if (class_atom_count[c] != natoms)
1688 foreach (mlc, arr[g]->member_atoms) {
1690 int atom_idx = (int) m->
rtindex - 1;
1691 AttrNumber attno =
ANCHOR(c, atom_idx);
1694 Form_pg_attribute attform;
1695 Oid mtype, mcoll, eqop, eqfunc;
1701 rte = (RangeTblEntry *) list_nth(q->rtable, atom_idx);
1702 atttup = SearchSysCache2(ATTNUM,
1703 ObjectIdGetDatum(rte->relid),
1704 Int16GetDatum(attno));
1705 if (!HeapTupleIsValid(atttup))
1707 attform = (Form_pg_attribute) GETSTRUCT(atttup);
1708 mtype = attform->atttypid;
1709 mtypmod = attform->atttypmod;
1710 mcoll = attform->attcollation;
1711 ReleaseSysCache(atttup);
1712 if (first_touching == NULL) {
1714 first_attno = attno;
1716 first_typmod = mtypmod;
1721 if (!OidIsValid(eqop))
1723 eqfunc = get_opcode(eqop);
1724 if (!OidIsValid(eqfunc))
1726 lv = makeVar(first_touching->
rtindex, first_attno,
1727 first_type, first_typmod, first_coll, 0);
1728 rv = makeVar(m->
rtindex, attno, mtype, mtypmod, mcoll, 0);
1729 eq = makeNode(OpExpr);
1731 eq->opfuncid = eqfunc;
1732 eq->opresulttype = BOOLOID;
1733 eq->opretset =
false;
1734 eq->opcollid = InvalidOid;
1735 eq->inputcollid = first_coll;
1736 eq->args = list_make2(lv, rv);
1739 lappend(arr[g]->inner_quals, eq);
1744 for (g = 0; g <= max_gid; g++)
1745 *groups_out = lappend(*groups_out, arr[g]);
1752 pfree(class_atom_count);
1753 pfree(class_atom_anchor_attno);
1758 pfree(in_targetlist);
1759 if (first_member_of_group)
1760 pfree(first_member_of_group);
1761 if (group_singleton_counter)
1762 pfree(group_singleton_counter);
1764 pfree(determined_in);
1765 if (class_atom_count_fd)
1766 pfree(class_atom_count_fd);
1767 if (atom_anchor_class)
1768 pfree(atom_anchor_class);
1773 pfree(class_atom_count);
1774 pfree(class_atom_anchor_attno);
1780 pfree(in_targetlist);
1781 if (first_member_of_group)
1782 pfree(first_member_of_group);
1783 if (group_singleton_counter)
1784 pfree(group_singleton_counter);
1786 pfree(determined_in);
1787 if (class_atom_count_fd)
1788 pfree(class_atom_count_fd);
1789 if (atom_anchor_class)
1790 pfree(atom_anchor_class);
1905 RangeTblEntry *base_rte,
1907 Index outer_rtindex,
1908 List *pushed_quals) {
1909 Query *inner = makeNode(Query);
1910 RangeTblRef *rtr = makeNode(RangeTblRef);
1911 FromExpr *jt = makeNode(FromExpr);
1912 RangeTblEntry *inner_rte;
1916 inner_rte = copyObject(base_rte);
1918 inner->commandType = CMD_SELECT;
1919 inner->canSetTag =
false;
1920 inner->rtable = list_make1(inner_rte);
1921#if PG_VERSION_NUM >= 160000
1927 if (base_rte->perminfoindex != 0
1928 && outer_src && outer_src->rteperminfos != NIL
1929 && (
int) base_rte->perminfoindex <= list_length(outer_src->rteperminfos)) {
1930 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
1931 outer_src->rteperminfos,
1932 base_rte->perminfoindex - 1);
1933 inner->rteperminfos = list_make1(copyObject(rpi));
1934 inner_rte->perminfoindex = 1;
1936 inner->rteperminfos = NIL;
1937 inner_rte->perminfoindex = 0;
1941 jt->fromlist = list_make1(rtr);
1943 inner->jointree = jt;
1945 inner->targetList = NIL;
1946 inner->distinctClause = NIL;
1947 inner->hasDistinctOn =
false;
1949 foreach (lc, proj_slots) {
1952 Form_pg_attribute attform;
1957 TargetEntry *te = makeNode(TargetEntry);
1958 SortGroupClause *sgc = makeNode(SortGroupClause);
1960 atttup = SearchSysCache2(ATTNUM,
1961 ObjectIdGetDatum(base_rte->relid),
1963 if (!HeapTupleIsValid(atttup))
1964 provsql_error(
"safe-query rewriter: cannot resolve attno %d of "
1966 (
int) slot->
base_attno, (
unsigned) base_rte->relid);
1967 attform = (Form_pg_attribute) GETSTRUCT(atttup);
1968 atttypid = attform->atttypid;
1969 atttypmod = attform->atttypmod;
1970 attcollation = attform->attcollation;
1971 ReleaseSysCache(atttup);
1974 v = makeVar(1, slot->
base_attno, atttypid, atttypmod, attcollation, 0);
1975 te->expr = (Expr *) v;
1976 te->resno = (AttrNumber) slot_idx;
1977 te->resname = psprintf(
"provsql_slot_%d", slot_idx);
1978 te->ressortgroupref = (Index) slot_idx;
1979 te->resorigtbl = base_rte->relid;
1981 te->resjunk =
false;
1982 inner->targetList = lappend(inner->targetList, te);
1984 sgc->tleSortGroupRef = (Index) slot_idx;
1985 get_sort_group_operators(atttypid,
true,
true,
false,
1986 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
1987 sgc->nulls_first =
false;
1988 inner->distinctClause = lappend(inner->distinctClause, sgc);
1996 if (pushed_quals != NIL) {
1998 List *remapped = NIL;
2001 foreach (qlc, pushed_quals) {
2002 Node *q = (Node *) copyObject(lfirst(qlc));
2004 remapped = lappend(remapped, q);
2006 if (list_length(remapped) == 1)
2007 inner->jointree->quals = (Node *) linitial(remapped);
2009 inner->jointree->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2076 Query *inner = makeNode(Query);
2077 FromExpr *jt = makeNode(FromExpr);
2079 RangeTblEntry *first_rte;
2081 Form_pg_attribute attform;
2088 int natoms = list_length(atoms);
2090 inner->commandType = CMD_SELECT;
2091 inner->canSetTag =
false;
2092 inner->rtable = NIL;
2093 inner->jointree = jt;
2096#if PG_VERSION_NUM >= 160000
2097 inner->rteperminfos = NIL;
2109 RangeTblEntry *src_rte =
2110 (RangeTblEntry *) list_nth(outer_src->rtable, (
int) sa->
rtindex - 1);
2111 RangeTblEntry *cloned = (RangeTblEntry *) copyObject(src_rte);
2112 RangeTblRef *rtr = makeNode(RangeTblRef);
2118#if PG_VERSION_NUM >= 160000
2119 if (cloned->perminfoindex != 0
2120 && outer_src->rteperminfos != NIL
2121 && (
int) cloned->perminfoindex
2122 <= list_length(outer_src->rteperminfos)) {
2123 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2124 outer_src->rteperminfos,
2125 cloned->perminfoindex - 1);
2126 inner->rteperminfos =
2127 lappend(inner->rteperminfos, copyObject(rpi));
2128 cloned->perminfoindex = (Index) list_length(inner->rteperminfos);
2130 cloned->perminfoindex = 0;
2134 inner->rtable = lappend(inner->rtable, cloned);
2135 rtr->rtindex = inner_idx;
2136 jt->fromlist = lappend(jt->fromlist, rtr);
2146 List *all_quals = NIL;
2148 all_quals = lappend(all_quals,
2149 copyObject((Node *) lfirst(lc)));
2154 all_quals = lappend(all_quals,
2155 copyObject((Node *) lfirst(qlc)));
2159 List *remapped = NIL;
2160 foreach (qlc, all_quals) {
2161 Node *qq = (Node *) lfirst(qlc);
2163 remapped = lappend(remapped, qq);
2165 if (remapped == NIL)
2167 else if (list_length(remapped) == 1)
2168 jt->quals = (Node *) linitial(remapped);
2170 jt->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2181 first_rte = (RangeTblEntry *)
2182 list_nth(outer_src->rtable, (
int) first_member->
rtindex - 1);
2184 inner->targetList = NIL;
2185 inner->groupClause = NIL;
2194 Bitmapset *emitted = NULL;
2198 RangeTblEntry *m_rte = (RangeTblEntry *)
2199 list_nth(outer_src->rtable, (
int) m->
rtindex - 1);
2204 SortGroupClause *sgc;
2206 if (bms_is_member((
int) slot->
outer_attno, emitted))
2208 emitted = bms_add_member(emitted, (
int) slot->
outer_attno);
2210 atttup = SearchSysCache2(ATTNUM,
2211 ObjectIdGetDatum(m_rte->relid),
2213 if (!HeapTupleIsValid(atttup))
2214 provsql_error(
"safe-query rewriter: cannot resolve attno %d of "
2215 "relation %u in inner sub-Query",
2216 (
int) slot->
base_attno, (
unsigned) m_rte->relid);
2217 attform = (Form_pg_attribute) GETSTRUCT(atttup);
2218 atttypid = attform->atttypid;
2219 atttypmod = attform->atttypmod;
2220 attcollation = attform->attcollation;
2221 ReleaseSysCache(atttup);
2223 te = makeNode(TargetEntry);
2224 sgc = makeNode(SortGroupClause);
2227 atttypid, atttypmod, attcollation, 0);
2228 te->expr = (Expr *) cv;
2230 te->resname = psprintf(
"provsql_slot_%d",
2233 te->resorigtbl = m_rte->relid;
2235 te->resjunk =
false;
2236 inner->targetList = lappend(inner->targetList, te);
2239 get_sort_group_operators(atttypid,
true,
true,
false,
2240 &sgc->sortop, &sgc->eqop, NULL,
2242 sgc->nulls_first =
false;
2243 inner->groupClause = lappend(inner->groupClause, sgc);
2249 (void) first_member; (void) first_rte;
2276 Query *q, List *atoms, List *groups,
2278 Query *outer = copyObject(q);
2280 List *new_rtable = NIL;
2281#if PG_VERSION_NUM >= 160000
2282 List *new_rteperminfos = NIL;
2284 List *new_fromlist = NIL;
2288 int ngroups = list_length(groups);
2289 bool *group_emitted = NULL;
2290 int total_atoms_in_groups = 0;
2296 group_emitted = palloc0(ngroups *
sizeof(
bool));
2297 foreach (lc, groups) {
2299 total_atoms_in_groups += list_length(gr->
member_atoms);
2307 if (outer->jointree)
2308 outer->jointree->quals =
2309 residual ? (Node *) copyObject(residual) : NULL;
2315 foreach (lc, outer->rtable) {
2316 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2323 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2324 Alias *eref = makeNode(Alias);
2328 eref->aliasname = rte->eref && rte->eref->aliasname
2329 ? pstrdup(rte->eref->aliasname)
2330 : pstrdup(
"provsql_wrap");
2331 eref->colnames = NIL;
2333 (void) lfirst(slot_lc);
2335 eref->colnames = lappend(eref->colnames,
2336 makeString(psprintf(
"provsql_slot_%d",
2340 new_rte->rtekind = RTE_SUBQUERY;
2341 new_rte->subquery = inner;
2342 new_rte->alias = NULL;
2343 new_rte->eref = eref;
2344 new_rte->inFromCl = rte->inFromCl;
2345 new_rte->lateral =
false;
2346#if PG_VERSION_NUM < 160000
2347 new_rte->requiredPerms = 0;
2352 new_rtable = lappend(new_rtable, new_rte);
2353 rtr = makeNode(RangeTblRef);
2354 rtr->rtindex = outer_pos;
2355 new_fromlist = lappend(new_fromlist, rtr);
2360 if (!group_emitted[g]) {
2362 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2363 Alias *eref = makeNode(Alias);
2365 int total_inner_cols = inner->targetList != NIL
2366 ? list_length(inner->targetList) : 0;
2368 eref->aliasname = pstrdup(
"provsql_group");
2369 eref->colnames = NIL;
2370 for (slot_idx = 1; slot_idx <= total_inner_cols; slot_idx++) {
2371 eref->colnames = lappend(eref->colnames,
2372 makeString(psprintf(
"provsql_slot_%d",
2376 new_rte->rtekind = RTE_SUBQUERY;
2377 new_rte->subquery = inner;
2378 new_rte->alias = NULL;
2379 new_rte->eref = eref;
2380 new_rte->inFromCl = rte->inFromCl;
2381 new_rte->lateral =
false;
2382#if PG_VERSION_NUM < 160000
2383 new_rte->requiredPerms = 0;
2388 new_rtable = lappend(new_rtable, new_rte);
2389 rtr = makeNode(RangeTblRef);
2390 rtr->rtindex = outer_pos;
2391 new_fromlist = lappend(new_fromlist, rtr);
2392 group_emitted[g] =
true;
2400 outer->rtable = new_rtable;
2401 if (outer->jointree)
2402 outer->jointree->fromlist = new_fromlist;
2403#if PG_VERSION_NUM >= 160000
2407 outer->rteperminfos = new_rteperminfos;
2423 outer->targetList = (List *)
2425 if (outer->jointree && outer->jointree->quals)
2426 outer->jointree->quals =
2430 pfree(group_emitted);
2439 provsql_notice(
"safe-query rewrite bailed: a Var has no projection "
2440 "slot in its (grouped or outer-wrap) atom");
2446 int total_slots = 0;
2447 int total_pushed = 0;
2448 int has_col_push = 0;
2449 foreach (lc, atoms) {
2456 initStringInfo(&buf);
2457 appendStringInfo(&buf,
2458 "safe-query rewrite fired: wrapped %d atoms with "
2459 "SELECT DISTINCT on %d total slot(s)",
2460 list_length(atoms) - total_atoms_in_groups,
2463 appendStringInfo(&buf,
2464 ", folded %d atom%s into %d inner sub-Quer%s",
2465 total_atoms_in_groups,
2466 total_atoms_in_groups == 1 ?
"" :
"s",
2467 ninner, ninner == 1 ?
"y" :
"ies");
2469 if (has_col_push || total_pushed > 0) {
2470 const char *sep =
" (";
2472 appendStringInfoString(&buf, sep);
2473 appendStringInfoString(&buf,
"column pushdown");
2476 if (total_pushed > 0) {
2477 appendStringInfoString(&buf, sep);
2478 appendStringInfo(&buf,
"%d atom-local qual%s pushed",
2479 total_pushed, total_pushed == 1 ?
"" :
"s");
2481 appendStringInfoChar(&buf,
')');
2637 List **per_atom_quals,
2641 int natoms = list_length(q->rtable);
2642 Query **inner_queries;
2644 List **inner_tlists;
2645 int *comp_inner_idx;
2646 int *atom_to_inner_idx;
2647 int *atom_to_inner_attno;
2648 Index *comp_outer_rtindex;
2651 List *conjuncts = NIL;
2652 List *outer_resid = NIL;
2657 inner_quals = palloc0(ncomp *
sizeof(List *));
2658 inner_tlists = palloc0(ncomp *
sizeof(List *));
2659 comp_inner_idx = palloc0(ncomp *
sizeof(
int));
2660 atom_to_inner_idx = palloc0(natoms *
sizeof(
int));
2661 atom_to_inner_attno = palloc0(natoms *
sizeof(
int));
2662 comp_outer_rtindex = palloc0(ncomp *
sizeof(Index));
2665 for (j = 0; j < natoms; j++) {
2666 int c = atom_to_comp[j];
2667 comp_inner_idx[c]++;
2668 atom_to_inner_idx[j] = comp_inner_idx[c];
2676 foreach (lc, q->targetList) {
2677 TargetEntry *te = (TargetEntry *) lfirst(lc);
2682 if (bms_is_empty(vctx.
varnos)) {
2690 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2692 if (v < 1 || v > natoms) {
2696 c = atom_to_comp[v - 1];
2699 else if (chosen != c) {
2705 inner_tlists[chosen] = lappend(inner_tlists[chosen], te);
2716 for (k = 0; k < ncomp; k++) {
2717 if (inner_tlists[k] == NIL) {
2718 TargetEntry *anchor = makeNode(TargetEntry);
2719 anchor->expr = (Expr *) makeConst(INT4OID, -1, InvalidOid,
2721 Int32GetDatum(1),
false,
true);
2723 anchor->resname = pstrdup(
"provsql_anchor");
2724 anchor->ressortgroupref = 1;
2725 anchor->resjunk =
false;
2726 inner_tlists[k] = list_make1(anchor);
2735 foreach (lc, conjuncts) {
2736 Node *qual = (Node *) lfirst(lc);
2740 bool keep_outer =
false;
2743 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2745 if (v < 1 || v > natoms) {
2749 c = atom_to_comp[v - 1];
2752 else if (chosen != c) {
2758 if (keep_outer || chosen < 0)
2759 outer_resid = lappend(outer_resid, qual);
2761 inner_quals[chosen] = lappend(inner_quals[chosen], qual);
2765 inner_queries = palloc0(ncomp *
sizeof(Query *));
2766 for (k = 0; k < ncomp; k++) {
2767 Query *inner = makeNode(Query);
2768 FromExpr *jt = makeNode(FromExpr);
2769 int inner_attno = 0;
2773 inner->commandType = CMD_SELECT;
2774 inner->canSetTag =
false;
2775 inner->rtable = NIL;
2776 inner->jointree = jt;
2779#if PG_VERSION_NUM >= 160000
2780 inner->rteperminfos = NIL;
2783 orig_to_inner = palloc0((natoms + 1) *
sizeof(
int));
2786 for (j = 0; j < natoms; j++) {
2787 RangeTblEntry *src_rte, *cloned;
2790 if (atom_to_comp[j] != k)
2792 src_rte = (RangeTblEntry *) list_nth(q->rtable, j);
2793 cloned = (RangeTblEntry *) copyObject(src_rte);
2794#if PG_VERSION_NUM >= 160000
2795 if (cloned->perminfoindex != 0
2796 && q->rteperminfos != NIL
2797 && (
int) cloned->perminfoindex <= list_length(q->rteperminfos)) {
2798 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2800 cloned->perminfoindex - 1);
2801 inner->rteperminfos =
2802 lappend(inner->rteperminfos, copyObject(rpi));
2803 cloned->perminfoindex = (Index) list_length(inner->rteperminfos);
2805 cloned->perminfoindex = 0;
2808 inner->rtable = lappend(inner->rtable, cloned);
2809 inner_rtindex = list_length(inner->rtable);
2810 orig_to_inner[j + 1] = inner_rtindex;
2811 rtr = makeNode(RangeTblRef);
2812 rtr->rtindex = inner_rtindex;
2813 jt->fromlist = lappend(jt->fromlist, rtr);
2823 foreach (qlc, inner_quals[k])
2824 all = lappend(all, copyObject((Node *) lfirst(qlc)));
2825 for (j = 0; j < natoms; j++) {
2826 if (atom_to_comp[j] != k)
2828 foreach (qlc, per_atom_quals[j])
2829 all = lappend(all, copyObject((Node *) lfirst(qlc)));
2833 List *remapped = NIL;
2836 foreach (qlc, all) {
2837 Node *qq = (Node *) lfirst(qlc);
2839 remapped = lappend(remapped, qq);
2841 if (list_length(remapped) == 1)
2842 jt->quals = (Node *) linitial(remapped);
2844 jt->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2852 inner->targetList = NIL;
2853 inner->groupClause = NIL;
2856 foreach (tlc, inner_tlists[k]) {
2857 TargetEntry *src_te = (TargetEntry *) lfirst(tlc);
2858 TargetEntry *new_te = (TargetEntry *) copyObject(src_te);
2860 SortGroupClause *sgc = makeNode(SortGroupClause);
2865 (Node *) new_te->expr, &rctx);
2868 new_te->resno = (AttrNumber) inner_attno;
2869 new_te->ressortgroupref = (Index) inner_sgr;
2870 new_te->resjunk =
false;
2881 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2882 if (v >= 1 && v <= natoms && atom_to_comp[v - 1] == k)
2883 atom_to_inner_attno[v - 1] = inner_attno;
2887 inner->targetList = lappend(inner->targetList, new_te);
2889 expr_type = exprType((Node *) new_te->expr);
2890 sgc->tleSortGroupRef = (Index) inner_sgr;
2891 get_sort_group_operators(expr_type,
true,
true,
false,
2892 &sgc->sortop, &sgc->eqop, NULL,
2894 sgc->nulls_first =
false;
2895 inner->groupClause = lappend(inner->groupClause, sgc);
2899 inner_queries[k] = inner;
2900 pfree(orig_to_inner);
2908 outer = copyObject(q);
2909 outer->rtable = NIL;
2910 outer->jointree->fromlist = NIL;
2911 outer->jointree->quals = (outer_resid == NIL) ? NULL
2912 : (list_length(outer_resid) == 1
2913 ? (Node *) linitial(outer_resid)
2914 : (Node *) makeBoolExpr(AND_EXPR,
2916#if PG_VERSION_NUM >= 160000
2917 outer->rteperminfos = NIL;
2919 for (k = 0; k < ncomp; k++) {
2920 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2921 Alias *eref = makeNode(Alias);
2925 eref->aliasname = psprintf(
"provsql_component_%d", k + 1);
2926 eref->colnames = NIL;
2927 foreach (tlc, inner_queries[k]->targetList) {
2928 TargetEntry *ite = (TargetEntry *) lfirst(tlc);
2930 eref->colnames = lappend(eref->colnames,
2931 makeString(ite->resname
2932 ? pstrdup(ite->resname)
2933 : psprintf(
"col_%d", slot_idx)));
2936 new_rte->rtekind = RTE_SUBQUERY;
2937 new_rte->subquery = inner_queries[k];
2938 new_rte->alias = NULL;
2939 new_rte->eref = eref;
2940 new_rte->inFromCl =
true;
2941 new_rte->lateral =
false;
2942#if PG_VERSION_NUM < 160000
2943 new_rte->requiredPerms = 0;
2946 outer->rtable = lappend(outer->rtable, new_rte);
2947 comp_outer_rtindex[k] = (Index) list_length(outer->rtable);
2949 RangeTblRef *rtr = makeNode(RangeTblRef);
2950 rtr->rtindex = comp_outer_rtindex[k];
2951 outer->jointree->fromlist = lappend(outer->jointree->fromlist, rtr);
2963 (Node *) outer->targetList, &tctx);
2964 if (outer->jointree->quals)
2965 outer->jointree->quals =
2969 provsql_notice(
"safe-query multi-component rewrite bailed: a Var "
2970 "has no exposed column in its component's inner "
2972 pfree(inner_queries);
2979 provsql_notice(
"safe-query multi-component rewrite fired: split %d "
2980 "atoms into %d disconnected component%s",
2981 natoms, ncomp, ncomp == 1 ?
"" :
"s");
2983 pfree(inner_queries);
2985 pfree(inner_tlists);
2986 pfree(comp_inner_idx);
2987 pfree(atom_to_inner_idx);
2988 pfree(atom_to_inner_attno);
2989 pfree(comp_outer_rtindex);
3036 Node **residual_in_out) {
3037 int natoms = list_length(q->rtable);
3039 List *eq_pairs = NIL;
3045 bool *is_constant_class;
3046 Const **class_const_value;
3047 List *all_const_conjuncts = NIL;
3055 expression_tree_walker((Node *) q->targetList,
3057 if (*residual_in_out)
3058 expression_tree_walker(*residual_in_out,
3060 if (per_atom_quals != NULL) {
3062 for (j = 0; j < natoms; j++) {
3064 foreach (qlc, per_atom_quals[j])
3065 expression_tree_walker((Node *) lfirst(qlc),
3069 nvars = list_length(vctx.
vars);
3073 vars_arr = palloc(nvars *
sizeof(Var *));
3074 cls = palloc(nvars *
sizeof(
int));
3076 foreach (lc, vctx.
vars) {
3077 vars_arr[i] = (Var *) lfirst(lc);
3083 if (*residual_in_out)
3085 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
3087 int li, ri, ci, cj, k;
3088 lv = (Var *) lfirst(lc);
3090 rv = (Var *) lfirst(lc);
3093 if (li < 0 || ri < 0)
3099 for (k = 0; k < nvars; k++)
3106 is_constant_class = palloc0(nvars *
sizeof(
bool));
3107 class_const_value = palloc0(nvars *
sizeof(Const *));
3108 if (per_atom_quals != NULL) {
3110 for (j = 0; j < natoms; j++) {
3112 foreach (qlc, per_atom_quals[j])
3113 all_const_conjuncts = lappend(all_const_conjuncts, lfirst(qlc));
3116 if (*residual_in_out)
3121 foreach (qlc, all_const_conjuncts) {
3122 Expr *e = (Expr *) lfirst(qlc);
3132 if (!is_constant_class[root]) {
3133 is_constant_class[root] =
true;
3134 class_const_value[root] = k;
3138 list_free(all_const_conjuncts);
3142 if (per_atom_quals != NULL) {
3143 for (i = 0; i < nvars; i++) {
3145 Var *vp = vars_arr[i];
3146 Const *k = class_const_value[root];
3148 bool already =
false;
3154 if (!is_constant_class[root] || k == NULL)
3156 if (vp->varno < 1 || (
int) vp->varno > natoms)
3158 atom_idx = (int) vp->varno - 1;
3159 foreach (qlc, per_atom_quals[atom_idx]) {
3161 &v_existing, &k_existing)
3162 && v_existing->varno == vp->varno
3163 && v_existing->varattno == vp->varattno) {
3171 if (eqop == InvalidOid)
3173 new_op = (OpExpr *) makeNode(OpExpr);
3174 new_op->opno = eqop;
3175 new_op->opfuncid = InvalidOid;
3176 new_op->opresulttype = BOOLOID;
3177 new_op->opretset =
false;
3178 new_op->opcollid = InvalidOid;
3179 new_op->inputcollid = vp->varcollid;
3180 new_op->args = list_make2(copyObject(vp), copyObject(k));
3181 new_op->location = -1;
3182 per_atom_quals[atom_idx] =
3183 lappend(per_atom_quals[atom_idx], new_op);
3201 if (*residual_in_out != NULL) {
3202 List *conjuncts = NIL;
3206 foreach (qlc, conjuncts) {
3207 Node *cj = (Node *) lfirst(qlc);
3210 bool all_constant =
true;
3211 bool any_var =
false;
3213 foreach (vlc, cv.
vars) {
3214 Var *v = (Var *) lfirst(vlc);
3217 if (idx < 0 || !is_constant_class[cls[idx]]) {
3218 all_constant =
false;
3223 if (any_var && all_constant)
3225 kept = lappend(kept, cj);
3228 *residual_in_out = NULL;
3229 else if (list_length(kept) == 1)
3230 *residual_in_out = (Node *) linitial(kept);
3232 *residual_in_out = (Node *) makeBoolExpr(AND_EXPR, kept, -1);
3233 list_free(conjuncts);
3236 pfree(is_constant_class);
3237 pfree(class_const_value);
3342 int natoms = list_length(q->rtable);
3347 List *eq_pairs = NIL;
3368 foreach (lc, q->rtable) {
3369 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3371 if (rte->rtekind != RTE_RELATION)
3373 foreach (lc2, seen_relids) {
3374 if (lfirst_oid(lc2) == rte->relid) {
3381 seen_relids = lappend_oid(seen_relids, rte->relid);
3383 list_free(seen_relids);
3393 expression_tree_walker((Node *) q->targetList,
3395 if (q->jointree && q->jointree->quals)
3396 expression_tree_walker(q->jointree->quals,
3398 nvars = list_length(vctx.
vars);
3402 vars_arr = palloc(nvars *
sizeof(Var *));
3403 cls = palloc(nvars *
sizeof(
int));
3405 foreach (lc, vctx.
vars) {
3406 vars_arr[i] = (Var *) lfirst(lc);
3410 if (q->jointree && q->jointree->quals)
3412 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
3414 int li, ri, ci, cj, k;
3415 lv = (Var *) lfirst(lc);
3417 rv = (Var *) lfirst(lc);
3420 if (li < 0 || ri < 0)
3426 for (k = 0; k < nvars; k++)
3435 keeper = palloc(natoms *
sizeof(
int));
3436 for (j = 0; j < natoms; j++)
3439 any_unified =
false;
3440 for (j = 0; j < natoms; j++) {
3441 RangeTblEntry *rte_j;
3444 bool all_pairs_unify;
3446 ListCell *lc_a, *lc_b;
3449 rte_j = (RangeTblEntry *) list_nth(q->rtable, j);
3450 if (rte_j->rtekind != RTE_RELATION)
3455 group = list_make1_int(j);
3456 for (k = j + 1; k < natoms; k++) {
3457 RangeTblEntry *rte_k = (RangeTblEntry *) list_nth(q->rtable, k);
3458 if (rte_k->rtekind != RTE_RELATION)
3460 if (rte_k->relid != rte_j->relid)
3462 group = lappend_int(group, k);
3464 if (list_length(group) < 2) {
3475 all_pairs_unify =
true;
3476 foreach (lc_a, group) {
3477 int aa = lfirst_int(lc_a);
3478 foreach (lc_b, group) {
3479 int bb = lfirst_int(lc_b);
3480 bool this_pair_unifies =
false;
3484 for (ki = 0; ki < keys.
key_n; ki++) {
3486 bool all_pk_equated =
true;
3488 for (kc = 0; kc < key->
col_n; kc++) {
3489 AttrNumber attno = key->
cols[kc];
3494 if (idx_a < 0 || idx_b < 0 || cls[idx_a] != cls[idx_b]) {
3495 all_pk_equated =
false;
3499 if (all_pk_equated) {
3500 this_pair_unifies =
true;
3504 if (!this_pair_unifies) {
3505 all_pairs_unify =
false;
3509 if (!all_pairs_unify)
3513 if (all_pairs_unify) {
3514 foreach (lc_a, group) {
3515 int aa = lfirst_int(lc_a);
3536 old_to_new = palloc0((natoms + 1) *
sizeof(
int));
3538 for (j = 0; j < natoms; j++) {
3540 while (keeper[root] != root)
3541 root = keeper[root];
3543 old_to_new[j + 1] = new_idx++;
3545 for (j = 0; j < natoms; j++) {
3547 while (keeper[root] != root)
3548 root = keeper[root];
3550 old_to_new[j + 1] = old_to_new[root + 1];
3555 for (j = 0; j < natoms; j++) {
3557 while (keeper[root] != root)
3558 root = keeper[root];
3560 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
3561 new_rtable = lappend(new_rtable, copyObject(rte));
3572 seen_new = palloc0((new_idx + 1) *
sizeof(
bool));
3574 foreach (lc, q->jointree->fromlist) {
3575 Node *n = (Node *) lfirst(lc);
3576 if (IsA(n, RangeTblRef)) {
3577 RangeTblRef *rtr = (RangeTblRef *) n;
3578 int new_no = old_to_new[rtr->rtindex];
3582 if (seen_new[new_no])
3584 seen_new[new_no] =
true;
3585 clone = (RangeTblRef *) copyObject(rtr);
3586 clone->rtindex = new_no;
3587 new_fromlist = lappend(new_fromlist, clone);
3589 new_fromlist = lappend(new_fromlist, copyObject(n));
3599 new_q = (Query *) copyObject(q);
3600 new_q->rtable = new_rtable;
3601 if (new_q->jointree)
3602 new_q->jointree->fromlist = new_fromlist;
3603#if PG_VERSION_NUM >= 160000
3611 new_q->targetList = (List *)
3613 if (new_q->jointree && new_q->jointree->quals)
3614 new_q->jointree->quals =
4570 int natoms = list_length(q->rtable);
4576 bool has_self_join =
false;
4578 List *eq_pairs = NIL;
4584 int *class_atom_count;
4585 int root_class = -1;
4586 int *col_pos_of_class;
4597 if (q->setOperations || q->hasAggs || q->hasWindowFuncs || q->limitCount
4598 || q->limitOffset || q->groupingSets || q->hasDistinctOn
4599 || q->hasSubLinks || q->rtable == NIL)
4603 foreach (lc, q->jointree->fromlist)
4604 if (!IsA((Node *) lfirst(lc), RangeTblRef))
4621 atom_relid = palloc(natoms *
sizeof(Oid));
4622 atom_rank = palloc(natoms *
sizeof(
int));
4623 atom_det = palloc0(natoms *
sizeof(
bool));
4625 foreach (lc, q->rtable) {
4626 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4628 AttrNumber provsql_attno;
4629 bool has_provsql_col, has_meta;
4630 if (rte->rtekind != RTE_RELATION) {
4631 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4634 has_provsql_col = provsql_attno != InvalidAttrNumber
4635 && get_atttype(rte->relid, provsql_attno) == constants->
OID_TYPE_UUID;
4637 if (!has_provsql_col && !has_meta) {
4643 HeapTuple class_tup = SearchSysCache1(RELOID, ObjectIdGetDatum(rte->relid));
4644 bool ok_relkind =
false;
4645 if (HeapTupleIsValid(class_tup)) {
4647 ((Form_pg_class) GETSTRUCT(class_tup))->relkind == RELKIND_RELATION;
4648 ReleaseSysCache(class_tup);
4650 if (!ok_relkind || has_superclass(rte->relid)) {
4651 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4654 atom_relid[i] = InvalidOid;
4662 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4664 atom_relid[i] = rte->relid;
4668 for (j = 0; j < i; j++)
4669 if (!atom_det[j] && atom_relid[j] == rte->relid) {
4670 atom_rank[i] = atom_rank[j]; has_self_join =
true;
break;
4672 if (atom_rank[i] < 0) atom_rank[i] = nranks++;
4676 if (n_tracked < 1) {
4677 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4686 (void) has_self_join;
4690 if (q->jointree && q->jointree->quals)
4692 nvars = list_length(vctx.
vars);
4693 if (nvars == 0) { pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL; }
4695 vars_arr = palloc(nvars *
sizeof(Var *));
4696 cls = palloc(nvars *
sizeof(
int));
4698 foreach (lc, vctx.
vars) { vars_arr[i] = (Var *) lfirst(lc); cls[i] = i; i++; }
4700 if (q->jointree && q->jointree->quals)
4702 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
4703 Var *lv = (Var *) lfirst(lc);
int li, ri, ci, cj, k;
4706 Var *rv = (Var *) lfirst(lc);
4710 if (li < 0 || ri < 0)
continue;
4711 ci = cls[li]; cj = cls[ri];
4712 if (ci == cj)
continue;
4713 for (k = 0; k < nvars; k++)
if (cls[k] == cj) cls[k] = ci;
4717 class_compact = palloc(nvars *
sizeof(
int));
4718 for (i = 0; i < nvars; i++) class_compact[i] = -1;
4719 for (i = 0; i < nvars; i++) {
4721 if (class_compact[r] < 0) class_compact[r] = nclasses++;
4723#define CCLASS(varidx) (class_compact[cls[(varidx)]])
4726 class_atom_count = palloc0(nclasses *
sizeof(
int));
4728 int *seen = palloc0((
size_t) nclasses * (
size_t) natoms *
sizeof(
int));
4729 for (i = 0; i < nvars; i++) {
4731 Index vno = vars_arr[i]->varno;
4733 if (vno < 1 || (
int) vno > natoms)
continue;
4735 if (atom_det[a])
continue;
4736 if (!seen[c * natoms + a]) { seen[c * natoms + a] = 1; class_atom_count[c]++; }
4742 for (i = 0; i < nclasses; i++)
4743 if (class_atom_count[i] == n_tracked) { root_class = i;
break; }
4744 if (root_class < 0) {
4746 provsql_notice(
"not inversion-free: no root variable (non-hierarchical)");
4753 col_pos_of_class = palloc0((
size_t) nranks * (
size_t) nclasses *
sizeof(
int));
4754 for (i = 0; i < nvars; i++) {
4756 Index vno = vars_arr[i]->varno;
4758 if (vno < 1 || (
int) vno > natoms)
continue;
4760 if (atom_det[a])
continue;
4761 rrank = atom_rank[a];
4762 pos = (int) vars_arr[i]->varattno;
4763 if (col_pos_of_class[rrank * nclasses + c] == 0)
4764 col_pos_of_class[rrank * nclasses + c] = pos;
4765 else if (col_pos_of_class[rrank * nclasses + c] != pos) {
4767 provsql_notice(
"not inversion-free: class at inconsistent column "
4768 "positions within one relation (inversion / self-equality)");
4776 prec = palloc0((
size_t) nclasses * (
size_t) nclasses *
sizeof(
int));
4777 for (i = 0; i < nvars; i++) {
4779 int posi = (int) vars_arr[i]->varattno;
4780 Index vno = vars_arr[i]->varno;
4781 if (vno >= 1 && (
int) vno <= natoms && atom_det[vno - 1])
4783 for (j = 0; j < nvars; j++) {
4785 if (vars_arr[j]->varno != vno)
continue;
4787 posj = (int) vars_arr[j]->varattno;
4788 if (posi < posj) prec[ci * nclasses + cj] = 1;
4789 else if (posi == posj && ci != cj) prec[ci * nclasses + cj] = 1;
4793 indeg = palloc0(nclasses *
sizeof(
int));
4794 for (i = 0; i < nclasses; i++)
4795 for (j = 0; j < nclasses; j++)
4796 if (i != j && prec[i * nclasses + j]) indeg[j]++;
4797 topo = palloc(nclasses *
sizeof(
int));
4799 bool *done = palloc0(nclasses *
sizeof(
bool));
4804 if (!done[root_class] && indeg[root_class] == 0) picked = root_class;
4805 for (i = 0; picked < 0 && i < nclasses; i++)
4806 if (!done[i] && indeg[i] == 0) picked = i;
4808 done[picked] =
true; topo[ntopo++] = picked;
4809 for (j = 0; j < nclasses; j++)
4810 if (!done[j] && prec[picked * nclasses + j]) indeg[j]--;
4812 }
while (picked >= 0);
4815 if (ntopo != nclasses) {
4818 "(inversion, e.g. symmetric closure R(x,y),R(y,x))");
4832 for (i = 0; i < nvars; i++) {
4833 int pos = (int) vars_arr[i]->varattno;
4838 for (i = 0; i < nvars; i++) {
4839 Index vno = vars_arr[i]->varno;
4841 if (vno < 1 || (
int) vno > natoms)
continue;
4843 if (atom_det[a])
continue;
4844 pos = (int) vars_arr[i]->varattno;