510 Query *q, Node *quals,
513 List *eq_pairs = NIL;
518 int natoms = list_length(q->rtable);
519 int *class_atom_count;
520 int *class_atom_anchor_attno;
522 List *atoms_out = NIL;
523 int *atom_group = NULL;
524 bool *in_targetlist = NULL;
525 int *first_member_of_group = NULL;
526 int *group_singleton_counter = NULL;
527 bool have_partial_class =
false;
528 int partial_first = -1;
529 Bitmapset *bridging_classes = NULL;
543 bool *determined_in = NULL;
544 int *class_atom_count_fd = NULL;
545 bool fd_aware_mode =
false;
546 int *atom_anchor_class = NULL;
564 expression_tree_walker((Node *) q->targetList,
569 nvars = list_length(vctx.
vars);
573 vars_arr = palloc(nvars *
sizeof(Var *));
574 cls = palloc(nvars *
sizeof(
int));
576 foreach (lc, vctx.
vars) {
577 vars_arr[i] = (Var *) lfirst(lc);
590 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
592 int li, ri, ci, cj, k;
593 lv = (Var *) lfirst(lc);
595 rv = (Var *) lfirst(lc);
598 if (li < 0 || ri < 0)
604 for (k = 0; k < nvars; k++)
611 class_atom_count = palloc0(nvars *
sizeof(
int));
612 class_atom_anchor_attno =
613 palloc0((
size_t) nvars * (
size_t) natoms *
sizeof(
int));
615#define ANCHOR(c, atom_idx) class_atom_anchor_attno[(c) * natoms + (atom_idx)]
617 for (i = 0; i < nvars; i++) {
620 varno = vars_arr[i]->varno;
621 if (varno < 1 || (
int) varno > natoms)
623 atom_idx = (int) varno - 1;
624 if (
ANCHOR(c, atom_idx) == 0) {
625 class_atom_count[c]++;
626 ANCHOR(c, atom_idx) = vars_arr[i]->varattno;
627 }
else if (
ANCHOR(c, atom_idx) != vars_arr[i]->varattno) {
632 class_atom_count[c] = natoms + 1;
657 palloc0((
size_t) nvars * (
size_t) natoms *
sizeof(
bool));
658#define DETERMINED(c, atom_idx) determined_in[(c) * natoms + (atom_idx)]
660 for (j = 0; j < natoms; j++) {
661 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
664 if (rte->rtekind != RTE_RELATION)
668 for (ki = 0; ki < keys.
key_n; ki++) {
670 bool all_anchored =
true;
683 for (kc = 0; kc < key->
col_n; kc++) {
688 all_anchored =
false;
691 if (class_atom_count[cls[idx]] < 2
692 || class_atom_count[cls[idx]] > natoms) {
693 all_anchored =
false;
701 for (vi = 0; vi < nvars; vi++) {
702 Var *vp = vars_arr[vi];
703 bool is_key_col =
false;
704 if (vp->varno != (Index) (j + 1))
706 for (kc = 0; kc < key->
col_n; kc++) {
707 if (vp->varattno == key->
cols[kc]) {
764 for (j = 0; j < natoms; j++) {
765 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
766 AttrNumber provsql_attno;
767 bool has_provsql_col;
770 Form_pg_class classform;
772 if (rte->rtekind != RTE_RELATION)
776 provsql_attno != InvalidAttrNumber
777 && get_atttype(rte->relid, provsql_attno) == constants->
OID_TYPE_UUID;
779 if (has_provsql_col || has_meta)
783 SearchSysCache1(RELOID, ObjectIdGetDatum(rte->relid));
784 if (!HeapTupleIsValid(class_tup))
786 classform = (Form_pg_class) GETSTRUCT(class_tup);
787 ok_relkind = (classform->relkind == RELKIND_RELATION);
788 ReleaseSysCache(class_tup);
792 if (has_superclass(rte->relid))
799 for (i = 0; i < nvars; i++) {
810 class_atom_count_fd = palloc0(nvars *
sizeof(
int));
811 for (i = 0; i < nvars; i++) {
815 if (class_atom_count[i] > natoms)
818 for (j = 0; j < natoms; j++) {
820 class_atom_count_fd[c]++;
829 in_targetlist = palloc0(nvars *
sizeof(
bool));
833 expression_tree_walker((Node *) q->targetList,
835 foreach (tlc, tlist_ctx.
vars) {
836 Var *v = (Var *) lfirst(tlc);
839 in_targetlist[idx] =
true;
846 for (i = 0; i < nvars; i++) {
849 if (class_atom_count[i] == natoms) {
886 if (root_class < 0 && determined_in != NULL) {
891 for (i = 0; i < nvars; i++) {
895 if (class_atom_count[c] >= 2 && class_atom_count[c] <= natoms) {
905 for (i = 0; i < nvars; i++)
906 if (in_targetlist[i]) { ok_fd =
false;
break; }
909 int ca = multi[0], cb = multi[1];
910 int ydet = -1, xdet = -1, satom = -1;
915 for (j = 0; j < natoms; j++) {
917 int yd = -1, xd = -1;
919 else if (
DETERMINED(cb, j)) { yd = cb; xd = ca; }
920 if (yd < 0) { ok_fd =
false;
break; }
921 if (ydet >= 0) { ok_fd =
false;
break; }
922 ydet = yd; xdet = xd; satom = j;
932 for (j = 0; j < natoms; j++) {
933 bool hx =
ANCHOR(xdet, j) != 0;
934 bool hy =
ANCHOR(ydet, j) != 0;
935 if (!hx && !hy) { ok_fd =
false;
break; }
936 if (hx && hy && j != satom){ ok_fd =
false;
break; }
955 for (j = 0; j < natoms; j++) {
957 bool hx =
ANCHOR(xdet, j) != 0;
969 if (
ANCHOR(ydet, j) != 0) {
984 atoms_out = lappend(atoms_out, sa);
986 *groups_out = list_make1(gr);
990 "fired (grouped %d-atom determining side on the "
994 pfree(class_atom_count);
995 pfree(class_atom_anchor_attno);
998 if (in_targetlist) pfree(in_targetlist);
999 if (determined_in) pfree(determined_in);
1000 if (class_atom_count_fd) pfree(class_atom_count_fd);
1044 if (root_class < 0) {
1045 bool eligible =
true;
1047 for (i = 0; i < nvars && eligible; i++) {
1050 if (class_atom_count[i] > natoms) {
1056 bool *atom_covered = palloc0(natoms *
sizeof(
bool));
1057 for (i = 0; i < nvars; i++) {
1059 Index vn = vars_arr[i]->varno;
1060 if (vn < 1 || (
int) vn > natoms)
1062 if (class_atom_count[c] > natoms)
1064 atom_covered[vn - 1] =
true;
1066 for (j = 0; j < natoms; j++) {
1067 if (!atom_covered[j]) {
1072 pfree(atom_covered);
1078 Bitmapset **atoms_fd = palloc0(nvars *
sizeof(Bitmapset *));
1079 int *class_reprs = palloc(nvars *
sizeof(
int));
1081 for (i = 0; i < nvars && eligible; i++) {
1084 if (class_atom_count[i] > natoms)
1086 if (class_atom_count[i] < 2)
1088 for (j = 0; j < natoms; j++) {
1090 atoms_fd[i] = bms_add_member(atoms_fd[i], j);
1092 class_reprs[nreprs++] = i;
1094 for (i = 0; i < nreprs && eligible; i++) {
1096 for (k = i + 1; k < nreprs && eligible; k++) {
1097 Bitmapset *a = atoms_fd[class_reprs[i]];
1098 Bitmapset *b = atoms_fd[class_reprs[k]];
1099 bool nested = bms_is_subset(a, b) || bms_is_subset(b, a);
1100 bool disjoint = !bms_overlap(a, b);
1101 if (!nested && !disjoint) {
1107 for (i = 0; i < nvars; i++)
1109 bms_free(atoms_fd[i]);
1131 atom_anchor_class = palloc(natoms *
sizeof(
int));
1132 for (j = 0; j < natoms; j++)
1133 atom_anchor_class[j] = -1;
1134 for (i = 0; i < nvars; i++) {
1138 if (class_atom_count[i] > natoms)
1140 if (class_atom_count[i] < 2)
1143 for (j = 0; j < natoms; j++) {
1145 && atom_anchor_class[j] < 0)
1146 atom_anchor_class[j] = c;
1149 for (j = 0; j < natoms; j++) {
1150 if (atom_anchor_class[j] >= 0)
1152 for (i = 0; i < nvars; i++) {
1155 if (class_atom_count[i] < 2 || class_atom_count[i] > natoms)
1158 atom_anchor_class[j] = i;
1167 for (j = 0; j < natoms; j++) {
1168 if (atom_anchor_class[j] < 0) {
1175 fd_aware_mode =
true;
1207 atom_group = palloc(natoms *
sizeof(
int));
1208 for (j = 0; j < natoms; j++)
1217 goto skip_partial_coverage;
1220 Bitmapset **sig = palloc0(natoms *
sizeof(Bitmapset *));
1221 bool has_outer_atom =
true;
1223 for (i = 0; i < nvars; i++) {
1227 if (class_atom_count[c] < 2)
1229 if (class_atom_count[c] > natoms)
1231 if (class_atom_count[c] == natoms)
1233 have_partial_class =
true;
1234 if (partial_first < 0)
1236 for (j = 0; j < natoms; j++) {
1238 sig[j] = bms_add_member(sig[j], c);
1242 if (have_partial_class) {
1243 has_outer_atom =
false;
1244 for (j = 0; j < natoms; j++) {
1245 if (bms_is_empty(sig[j])) {
1246 has_outer_atom =
true;
1252 if (have_partial_class && has_outer_atom) {
1255 for (j = 0; j < natoms; j++)
1256 atom_group[j] = bms_is_empty(sig[j]) ? -1 : 0;
1257 }
else if (have_partial_class) {
1271 Bitmapset **group_sigs;
1277 group_sigs = palloc0(natoms *
sizeof(Bitmapset *));
1278 for (j = 0; j < natoms; j++) {
1280 for (g = 0; g < ngroups; g++) {
1281 if (bms_equal(group_sigs[g], sig[j])) {
1288 atom_group[j] = ngroups;
1289 group_sigs[ngroups] = sig[j];
1297 for (i = 0; i < nvars; i++) {
1299 Bitmapset *touched_groups = NULL;
1303 if (class_atom_count[c] < 2 || class_atom_count[c] >= natoms)
1305 for (jj = 0; jj < natoms; jj++) {
1307 touched_groups = bms_add_member(touched_groups,
1310 if (bms_num_members(touched_groups) > 1)
1311 bridging_classes = bms_add_member(bridging_classes, c);
1312 bms_free(touched_groups);
1318 if (!bms_is_empty(bridging_classes)) {
1319 int *parent = palloc(ngroups *
sizeof(
int));
1320 int *super = palloc(ngroups *
sizeof(
int));
1324 for (g = 0; g < ngroups; g++) {
1330 while ((c = bms_next_member(bridging_classes, c)) >= 0) {
1333 for (jj = 0; jj < natoms; jj++) {
1337 gj = atom_group[jj];
1344 while (parent[ra] != ra) ra = parent[ra];
1346 while (parent[rb] != rb) rb = parent[rb];
1352 for (g = 0; g < ngroups; g++) {
1354 while (parent[r] != r) r = parent[r];
1356 super[r] = next_super++;
1357 super[g] = super[r];
1360 for (j = 0; j < natoms; j++) {
1361 if (atom_group[j] >= 0)
1362 atom_group[j] = super[atom_group[j]];
1367 bms_free(bridging_classes);
1368 bridging_classes = NULL;
1372 for (j = 0; j < natoms; j++) bms_free(sig[j]);
1376skip_partial_coverage:
1387 int g, ngroups_local = 0;
1388 for (j = 0; j < natoms; j++)
1389 if (atom_group[j] >= 0 && atom_group[j] + 1 > ngroups_local)
1390 ngroups_local = atom_group[j] + 1;
1391 first_member_of_group = palloc(natoms *
sizeof(
int));
1392 group_singleton_counter = palloc(natoms *
sizeof(
int));
1393 for (g = 0; g < ngroups_local; g++) {
1394 first_member_of_group[g] = -1;
1395 group_singleton_counter[g] = 0;
1397 for (j = 0; j < natoms; j++) {
1398 int g_loc = atom_group[j];
1399 if (g_loc >= 0 && first_member_of_group[g_loc] < 0)
1400 first_member_of_group[g_loc] = j;
1419 for (i = 0; i < nvars; i++) {
1421 int atom_idx = (int) vars_arr[i]->varno - 1;
1422 if (fd_aware_mode) {
1423 if (class_atom_count[c] >= 2 && class_atom_count[c] <= natoms)
1425 if (class_atom_count[c] == 1 && in_targetlist[i])
1428 provsql_notice(
"safe-query rewriter (fd-aware): Var (varno=%u, varattno=%d) "
1429 "belongs to a class with no outer slot",
1430 (
unsigned) vars_arr[i]->varno,
1431 (
int) vars_arr[i]->varattno);
1435 if (class_atom_count[c] == natoms)
1437 if (class_atom_count[c] >= 2 && class_atom_count[c] < natoms
1438 && atom_group[atom_idx] >= 0)
1447 if (class_atom_count[c] == 1 && in_targetlist[i])
1450 provsql_notice(
"safe-query rewriter: Var (varno=%u, varattno=%d) "
1451 "belongs to a class that does not match any outer or "
1452 "inner-group slot -- rewrite scope does not yet cover "
1454 (
unsigned) vars_arr[i]->varno,
1455 (
int) vars_arr[i]->varattno);
1474 for (j = 0; j < natoms; j++) {
1477 int local_root = fd_aware_mode ? atom_anchor_class[j] : root_class;
1479 sa->
rtindex = (Index) (j + 1);
1495 for (i = 0; i < nvars; i++) {
1497 if (cls[i] != i || i == local_root)
1499 if (fd_aware_mode) {
1505 if (class_atom_count[i] < 2 || class_atom_count[i] > natoms)
1507 }
else if (class_atom_count[i] != natoms) {
1528 for (i = 0; i < nvars; i++) {
1531 bool already_have =
false;
1532 bool is_first_member;
1533 if (!in_targetlist[i])
1535 if (class_atom_count[cls[i]] != 1)
1537 if ((
int) vars_arr[i]->varno - 1 != j)
1541 if (ex->
base_attno == vars_arr[i]->varattno) {
1542 already_have =
true;
1551 is_first_member = (sa->
group_id >= 0
1552 && first_member_of_group[sa->
group_id] == j);
1553 if (sa->
group_id < 0 || is_first_member) {
1555 (AttrNumber) (list_length(sa->
proj_slots) + 1);
1557 group_singleton_counter[sa->
group_id]++;
1559 (AttrNumber) group_singleton_counter[sa->
group_id];
1567 && first_member_of_group[sa->
group_id] == j) {
1568 group_singleton_counter[sa->
group_id] =
1583 RangeTblEntry *rte =
1584 (RangeTblEntry *) list_nth(q->rtable, j);
1591 "has an empty block_key (whole table is one "
1592 "block); the wrap's DISTINCT could split the "
1593 "block across multiple output rows, deferred",
1612 "has block_key column attno=%d outside the "
1613 "projection slots; the wrap would split a "
1623 atoms_out = lappend(atoms_out, sa);
1632 if (have_partial_class) {
1637 foreach (alc, atoms_out) {
1643 for (g = 0; g <= max_gid; g++) {
1650 foreach (alc, atoms_out) {
1672 for (g = 0; g <= max_gid; g++) {
1673 for (i = 0; i < nvars; i++) {
1676 AttrNumber first_attno = 0;
1677 Oid first_type = InvalidOid;
1678 int32 first_typmod = -1;
1679 Oid first_coll = InvalidOid;
1683 if (class_atom_count[c] != natoms)
1685 foreach (mlc, arr[g]->member_atoms) {
1687 int atom_idx = (int) m->
rtindex - 1;
1688 AttrNumber attno =
ANCHOR(c, atom_idx);
1691 Form_pg_attribute attform;
1692 Oid mtype, mcoll, eqop, eqfunc;
1698 rte = (RangeTblEntry *) list_nth(q->rtable, atom_idx);
1699 atttup = SearchSysCache2(ATTNUM,
1700 ObjectIdGetDatum(rte->relid),
1701 Int16GetDatum(attno));
1702 if (!HeapTupleIsValid(atttup))
1704 attform = (Form_pg_attribute) GETSTRUCT(atttup);
1705 mtype = attform->atttypid;
1706 mtypmod = attform->atttypmod;
1707 mcoll = attform->attcollation;
1708 ReleaseSysCache(atttup);
1709 if (first_touching == NULL) {
1711 first_attno = attno;
1713 first_typmod = mtypmod;
1718 if (!OidIsValid(eqop))
1720 eqfunc = get_opcode(eqop);
1721 if (!OidIsValid(eqfunc))
1723 lv = makeVar(first_touching->
rtindex, first_attno,
1724 first_type, first_typmod, first_coll, 0);
1725 rv = makeVar(m->
rtindex, attno, mtype, mtypmod, mcoll, 0);
1726 eq = makeNode(OpExpr);
1728 eq->opfuncid = eqfunc;
1729 eq->opresulttype = BOOLOID;
1730 eq->opretset =
false;
1731 eq->opcollid = InvalidOid;
1732 eq->inputcollid = first_coll;
1733 eq->args = list_make2(lv, rv);
1736 lappend(arr[g]->inner_quals, eq);
1741 for (g = 0; g <= max_gid; g++)
1742 *groups_out = lappend(*groups_out, arr[g]);
1749 pfree(class_atom_count);
1750 pfree(class_atom_anchor_attno);
1755 pfree(in_targetlist);
1756 if (first_member_of_group)
1757 pfree(first_member_of_group);
1758 if (group_singleton_counter)
1759 pfree(group_singleton_counter);
1761 pfree(determined_in);
1762 if (class_atom_count_fd)
1763 pfree(class_atom_count_fd);
1764 if (atom_anchor_class)
1765 pfree(atom_anchor_class);
1770 pfree(class_atom_count);
1771 pfree(class_atom_anchor_attno);
1777 pfree(in_targetlist);
1778 if (first_member_of_group)
1779 pfree(first_member_of_group);
1780 if (group_singleton_counter)
1781 pfree(group_singleton_counter);
1783 pfree(determined_in);
1784 if (class_atom_count_fd)
1785 pfree(class_atom_count_fd);
1786 if (atom_anchor_class)
1787 pfree(atom_anchor_class);
1902 RangeTblEntry *base_rte,
1904 Index outer_rtindex,
1905 List *pushed_quals) {
1906 Query *inner = makeNode(Query);
1907 RangeTblRef *rtr = makeNode(RangeTblRef);
1908 FromExpr *jt = makeNode(FromExpr);
1909 RangeTblEntry *inner_rte;
1913 inner_rte = copyObject(base_rte);
1915 inner->commandType = CMD_SELECT;
1916 inner->canSetTag =
false;
1917 inner->rtable = list_make1(inner_rte);
1918#if PG_VERSION_NUM >= 160000
1924 if (base_rte->perminfoindex != 0
1925 && outer_src && outer_src->rteperminfos != NIL
1926 && (
int) base_rte->perminfoindex <= list_length(outer_src->rteperminfos)) {
1927 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
1928 outer_src->rteperminfos,
1929 base_rte->perminfoindex - 1);
1930 inner->rteperminfos = list_make1(copyObject(rpi));
1931 inner_rte->perminfoindex = 1;
1933 inner->rteperminfos = NIL;
1934 inner_rte->perminfoindex = 0;
1938 jt->fromlist = list_make1(rtr);
1940 inner->jointree = jt;
1942 inner->targetList = NIL;
1943 inner->distinctClause = NIL;
1944 inner->hasDistinctOn =
false;
1946 foreach (lc, proj_slots) {
1949 Form_pg_attribute attform;
1954 TargetEntry *te = makeNode(TargetEntry);
1955 SortGroupClause *sgc = makeNode(SortGroupClause);
1957 atttup = SearchSysCache2(ATTNUM,
1958 ObjectIdGetDatum(base_rte->relid),
1960 if (!HeapTupleIsValid(atttup))
1961 provsql_error(
"safe-query rewriter: cannot resolve attno %d of "
1963 (
int) slot->
base_attno, (
unsigned) base_rte->relid);
1964 attform = (Form_pg_attribute) GETSTRUCT(atttup);
1965 atttypid = attform->atttypid;
1966 atttypmod = attform->atttypmod;
1967 attcollation = attform->attcollation;
1968 ReleaseSysCache(atttup);
1971 v = makeVar(1, slot->
base_attno, atttypid, atttypmod, attcollation, 0);
1972 te->expr = (Expr *) v;
1973 te->resno = (AttrNumber) slot_idx;
1974 te->resname = psprintf(
"provsql_slot_%d", slot_idx);
1975 te->ressortgroupref = (Index) slot_idx;
1976 te->resorigtbl = base_rte->relid;
1978 te->resjunk =
false;
1979 inner->targetList = lappend(inner->targetList, te);
1981 sgc->tleSortGroupRef = (Index) slot_idx;
1982 get_sort_group_operators(atttypid,
true,
true,
false,
1983 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
1984 sgc->nulls_first =
false;
1985 inner->distinctClause = lappend(inner->distinctClause, sgc);
1993 if (pushed_quals != NIL) {
1995 List *remapped = NIL;
1998 foreach (qlc, pushed_quals) {
1999 Node *q = (Node *) copyObject(lfirst(qlc));
2001 remapped = lappend(remapped, q);
2003 if (list_length(remapped) == 1)
2004 inner->jointree->quals = (Node *) linitial(remapped);
2006 inner->jointree->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2073 Query *inner = makeNode(Query);
2074 FromExpr *jt = makeNode(FromExpr);
2076 RangeTblEntry *first_rte;
2078 Form_pg_attribute attform;
2085 int natoms = list_length(atoms);
2087 inner->commandType = CMD_SELECT;
2088 inner->canSetTag =
false;
2089 inner->rtable = NIL;
2090 inner->jointree = jt;
2093#if PG_VERSION_NUM >= 160000
2094 inner->rteperminfos = NIL;
2106 RangeTblEntry *src_rte =
2107 (RangeTblEntry *) list_nth(outer_src->rtable, (
int) sa->
rtindex - 1);
2108 RangeTblEntry *cloned = (RangeTblEntry *) copyObject(src_rte);
2109 RangeTblRef *rtr = makeNode(RangeTblRef);
2115#if PG_VERSION_NUM >= 160000
2116 if (cloned->perminfoindex != 0
2117 && outer_src->rteperminfos != NIL
2118 && (
int) cloned->perminfoindex
2119 <= list_length(outer_src->rteperminfos)) {
2120 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2121 outer_src->rteperminfos,
2122 cloned->perminfoindex - 1);
2123 inner->rteperminfos =
2124 lappend(inner->rteperminfos, copyObject(rpi));
2125 cloned->perminfoindex = (Index) list_length(inner->rteperminfos);
2127 cloned->perminfoindex = 0;
2131 inner->rtable = lappend(inner->rtable, cloned);
2132 rtr->rtindex = inner_idx;
2133 jt->fromlist = lappend(jt->fromlist, rtr);
2143 List *all_quals = NIL;
2145 all_quals = lappend(all_quals,
2146 copyObject((Node *) lfirst(lc)));
2151 all_quals = lappend(all_quals,
2152 copyObject((Node *) lfirst(qlc)));
2156 List *remapped = NIL;
2157 foreach (qlc, all_quals) {
2158 Node *qq = (Node *) lfirst(qlc);
2160 remapped = lappend(remapped, qq);
2162 if (remapped == NIL)
2164 else if (list_length(remapped) == 1)
2165 jt->quals = (Node *) linitial(remapped);
2167 jt->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2178 first_rte = (RangeTblEntry *)
2179 list_nth(outer_src->rtable, (
int) first_member->
rtindex - 1);
2181 inner->targetList = NIL;
2182 inner->groupClause = NIL;
2191 Bitmapset *emitted = NULL;
2195 RangeTblEntry *m_rte = (RangeTblEntry *)
2196 list_nth(outer_src->rtable, (
int) m->
rtindex - 1);
2201 SortGroupClause *sgc;
2203 if (bms_is_member((
int) slot->
outer_attno, emitted))
2205 emitted = bms_add_member(emitted, (
int) slot->
outer_attno);
2207 atttup = SearchSysCache2(ATTNUM,
2208 ObjectIdGetDatum(m_rte->relid),
2210 if (!HeapTupleIsValid(atttup))
2211 provsql_error(
"safe-query rewriter: cannot resolve attno %d of "
2212 "relation %u in inner sub-Query",
2213 (
int) slot->
base_attno, (
unsigned) m_rte->relid);
2214 attform = (Form_pg_attribute) GETSTRUCT(atttup);
2215 atttypid = attform->atttypid;
2216 atttypmod = attform->atttypmod;
2217 attcollation = attform->attcollation;
2218 ReleaseSysCache(atttup);
2220 te = makeNode(TargetEntry);
2221 sgc = makeNode(SortGroupClause);
2224 atttypid, atttypmod, attcollation, 0);
2225 te->expr = (Expr *) cv;
2227 te->resname = psprintf(
"provsql_slot_%d",
2230 te->resorigtbl = m_rte->relid;
2232 te->resjunk =
false;
2233 inner->targetList = lappend(inner->targetList, te);
2236 get_sort_group_operators(atttypid,
true,
true,
false,
2237 &sgc->sortop, &sgc->eqop, NULL,
2239 sgc->nulls_first =
false;
2240 inner->groupClause = lappend(inner->groupClause, sgc);
2246 (void) first_member; (void) first_rte;
2273 Query *q, List *atoms, List *groups,
2275 Query *outer = copyObject(q);
2277 List *new_rtable = NIL;
2278#if PG_VERSION_NUM >= 160000
2279 List *new_rteperminfos = NIL;
2281 List *new_fromlist = NIL;
2285 int ngroups = list_length(groups);
2286 bool *group_emitted = NULL;
2287 int total_atoms_in_groups = 0;
2293 group_emitted = palloc0(ngroups *
sizeof(
bool));
2294 foreach (lc, groups) {
2296 total_atoms_in_groups += list_length(gr->
member_atoms);
2304 if (outer->jointree)
2305 outer->jointree->quals =
2306 residual ? (Node *) copyObject(residual) : NULL;
2312 foreach (lc, outer->rtable) {
2313 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2320 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2321 Alias *eref = makeNode(Alias);
2325 eref->aliasname = rte->eref && rte->eref->aliasname
2326 ? pstrdup(rte->eref->aliasname)
2327 : pstrdup(
"provsql_wrap");
2328 eref->colnames = NIL;
2330 (void) lfirst(slot_lc);
2332 eref->colnames = lappend(eref->colnames,
2333 makeString(psprintf(
"provsql_slot_%d",
2337 new_rte->rtekind = RTE_SUBQUERY;
2338 new_rte->subquery = inner;
2339 new_rte->alias = NULL;
2340 new_rte->eref = eref;
2341 new_rte->inFromCl = rte->inFromCl;
2342 new_rte->lateral =
false;
2343#if PG_VERSION_NUM < 160000
2344 new_rte->requiredPerms = 0;
2349 new_rtable = lappend(new_rtable, new_rte);
2350 rtr = makeNode(RangeTblRef);
2351 rtr->rtindex = outer_pos;
2352 new_fromlist = lappend(new_fromlist, rtr);
2357 if (!group_emitted[g]) {
2359 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2360 Alias *eref = makeNode(Alias);
2362 int total_inner_cols = inner->targetList != NIL
2363 ? list_length(inner->targetList) : 0;
2365 eref->aliasname = pstrdup(
"provsql_group");
2366 eref->colnames = NIL;
2367 for (slot_idx = 1; slot_idx <= total_inner_cols; slot_idx++) {
2368 eref->colnames = lappend(eref->colnames,
2369 makeString(psprintf(
"provsql_slot_%d",
2373 new_rte->rtekind = RTE_SUBQUERY;
2374 new_rte->subquery = inner;
2375 new_rte->alias = NULL;
2376 new_rte->eref = eref;
2377 new_rte->inFromCl = rte->inFromCl;
2378 new_rte->lateral =
false;
2379#if PG_VERSION_NUM < 160000
2380 new_rte->requiredPerms = 0;
2385 new_rtable = lappend(new_rtable, new_rte);
2386 rtr = makeNode(RangeTblRef);
2387 rtr->rtindex = outer_pos;
2388 new_fromlist = lappend(new_fromlist, rtr);
2389 group_emitted[g] =
true;
2397 outer->rtable = new_rtable;
2398 if (outer->jointree)
2399 outer->jointree->fromlist = new_fromlist;
2400#if PG_VERSION_NUM >= 160000
2404 outer->rteperminfos = new_rteperminfos;
2420 outer->targetList = (List *)
2422 if (outer->jointree && outer->jointree->quals)
2423 outer->jointree->quals =
2427 pfree(group_emitted);
2436 provsql_notice(
"safe-query rewrite bailed: a Var has no projection "
2437 "slot in its (grouped or outer-wrap) atom");
2443 int total_slots = 0;
2444 int total_pushed = 0;
2445 int has_col_push = 0;
2446 foreach (lc, atoms) {
2453 initStringInfo(&buf);
2454 appendStringInfo(&buf,
2455 "safe-query rewrite fired: wrapped %d atoms with "
2456 "SELECT DISTINCT on %d total slot(s)",
2457 list_length(atoms) - total_atoms_in_groups,
2460 appendStringInfo(&buf,
2461 ", folded %d atom%s into %d inner sub-Quer%s",
2462 total_atoms_in_groups,
2463 total_atoms_in_groups == 1 ?
"" :
"s",
2464 ninner, ninner == 1 ?
"y" :
"ies");
2466 if (has_col_push || total_pushed > 0) {
2467 const char *sep =
" (";
2469 appendStringInfoString(&buf, sep);
2470 appendStringInfoString(&buf,
"column pushdown");
2473 if (total_pushed > 0) {
2474 appendStringInfoString(&buf, sep);
2475 appendStringInfo(&buf,
"%d atom-local qual%s pushed",
2476 total_pushed, total_pushed == 1 ?
"" :
"s");
2478 appendStringInfoChar(&buf,
')');
2634 List **per_atom_quals,
2638 int natoms = list_length(q->rtable);
2639 Query **inner_queries;
2641 List **inner_tlists;
2642 int *comp_inner_idx;
2643 int *atom_to_inner_idx;
2644 int *atom_to_inner_attno;
2645 Index *comp_outer_rtindex;
2648 List *conjuncts = NIL;
2649 List *outer_resid = NIL;
2654 inner_quals = palloc0(ncomp *
sizeof(List *));
2655 inner_tlists = palloc0(ncomp *
sizeof(List *));
2656 comp_inner_idx = palloc0(ncomp *
sizeof(
int));
2657 atom_to_inner_idx = palloc0(natoms *
sizeof(
int));
2658 atom_to_inner_attno = palloc0(natoms *
sizeof(
int));
2659 comp_outer_rtindex = palloc0(ncomp *
sizeof(Index));
2662 for (j = 0; j < natoms; j++) {
2663 int c = atom_to_comp[j];
2664 comp_inner_idx[c]++;
2665 atom_to_inner_idx[j] = comp_inner_idx[c];
2673 foreach (lc, q->targetList) {
2674 TargetEntry *te = (TargetEntry *) lfirst(lc);
2679 if (bms_is_empty(vctx.
varnos)) {
2687 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2689 if (v < 1 || v > natoms) {
2693 c = atom_to_comp[v - 1];
2696 else if (chosen != c) {
2702 inner_tlists[chosen] = lappend(inner_tlists[chosen], te);
2713 for (k = 0; k < ncomp; k++) {
2714 if (inner_tlists[k] == NIL) {
2715 TargetEntry *anchor = makeNode(TargetEntry);
2716 anchor->expr = (Expr *) makeConst(INT4OID, -1, InvalidOid,
2718 Int32GetDatum(1),
false,
true);
2720 anchor->resname = pstrdup(
"provsql_anchor");
2721 anchor->ressortgroupref = 1;
2722 anchor->resjunk =
false;
2723 inner_tlists[k] = list_make1(anchor);
2732 foreach (lc, conjuncts) {
2733 Node *qual = (Node *) lfirst(lc);
2737 bool keep_outer =
false;
2740 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2742 if (v < 1 || v > natoms) {
2746 c = atom_to_comp[v - 1];
2749 else if (chosen != c) {
2755 if (keep_outer || chosen < 0)
2756 outer_resid = lappend(outer_resid, qual);
2758 inner_quals[chosen] = lappend(inner_quals[chosen], qual);
2762 inner_queries = palloc0(ncomp *
sizeof(Query *));
2763 for (k = 0; k < ncomp; k++) {
2764 Query *inner = makeNode(Query);
2765 FromExpr *jt = makeNode(FromExpr);
2766 int inner_attno = 0;
2770 inner->commandType = CMD_SELECT;
2771 inner->canSetTag =
false;
2772 inner->rtable = NIL;
2773 inner->jointree = jt;
2776#if PG_VERSION_NUM >= 160000
2777 inner->rteperminfos = NIL;
2780 orig_to_inner = palloc0((natoms + 1) *
sizeof(
int));
2783 for (j = 0; j < natoms; j++) {
2784 RangeTblEntry *src_rte, *cloned;
2787 if (atom_to_comp[j] != k)
2789 src_rte = (RangeTblEntry *) list_nth(q->rtable, j);
2790 cloned = (RangeTblEntry *) copyObject(src_rte);
2791#if PG_VERSION_NUM >= 160000
2792 if (cloned->perminfoindex != 0
2793 && q->rteperminfos != NIL
2794 && (
int) cloned->perminfoindex <= list_length(q->rteperminfos)) {
2795 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2797 cloned->perminfoindex - 1);
2798 inner->rteperminfos =
2799 lappend(inner->rteperminfos, copyObject(rpi));
2800 cloned->perminfoindex = (Index) list_length(inner->rteperminfos);
2802 cloned->perminfoindex = 0;
2805 inner->rtable = lappend(inner->rtable, cloned);
2806 inner_rtindex = list_length(inner->rtable);
2807 orig_to_inner[j + 1] = inner_rtindex;
2808 rtr = makeNode(RangeTblRef);
2809 rtr->rtindex = inner_rtindex;
2810 jt->fromlist = lappend(jt->fromlist, rtr);
2820 foreach (qlc, inner_quals[k])
2821 all = lappend(all, copyObject((Node *) lfirst(qlc)));
2822 for (j = 0; j < natoms; j++) {
2823 if (atom_to_comp[j] != k)
2825 foreach (qlc, per_atom_quals[j])
2826 all = lappend(all, copyObject((Node *) lfirst(qlc)));
2830 List *remapped = NIL;
2833 foreach (qlc, all) {
2834 Node *qq = (Node *) lfirst(qlc);
2836 remapped = lappend(remapped, qq);
2838 if (list_length(remapped) == 1)
2839 jt->quals = (Node *) linitial(remapped);
2841 jt->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2849 inner->targetList = NIL;
2850 inner->groupClause = NIL;
2853 foreach (tlc, inner_tlists[k]) {
2854 TargetEntry *src_te = (TargetEntry *) lfirst(tlc);
2855 TargetEntry *new_te = (TargetEntry *) copyObject(src_te);
2857 SortGroupClause *sgc = makeNode(SortGroupClause);
2862 (Node *) new_te->expr, &rctx);
2865 new_te->resno = (AttrNumber) inner_attno;
2866 new_te->ressortgroupref = (Index) inner_sgr;
2867 new_te->resjunk =
false;
2878 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2879 if (v >= 1 && v <= natoms && atom_to_comp[v - 1] == k)
2880 atom_to_inner_attno[v - 1] = inner_attno;
2884 inner->targetList = lappend(inner->targetList, new_te);
2886 expr_type = exprType((Node *) new_te->expr);
2887 sgc->tleSortGroupRef = (Index) inner_sgr;
2888 get_sort_group_operators(expr_type,
true,
true,
false,
2889 &sgc->sortop, &sgc->eqop, NULL,
2891 sgc->nulls_first =
false;
2892 inner->groupClause = lappend(inner->groupClause, sgc);
2896 inner_queries[k] = inner;
2897 pfree(orig_to_inner);
2905 outer = copyObject(q);
2906 outer->rtable = NIL;
2907 outer->jointree->fromlist = NIL;
2908 outer->jointree->quals = (outer_resid == NIL) ? NULL
2909 : (list_length(outer_resid) == 1
2910 ? (Node *) linitial(outer_resid)
2911 : (Node *) makeBoolExpr(AND_EXPR,
2913#if PG_VERSION_NUM >= 160000
2914 outer->rteperminfos = NIL;
2916 for (k = 0; k < ncomp; k++) {
2917 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2918 Alias *eref = makeNode(Alias);
2922 eref->aliasname = psprintf(
"provsql_component_%d", k + 1);
2923 eref->colnames = NIL;
2924 foreach (tlc, inner_queries[k]->targetList) {
2925 TargetEntry *ite = (TargetEntry *) lfirst(tlc);
2927 eref->colnames = lappend(eref->colnames,
2928 makeString(ite->resname
2929 ? pstrdup(ite->resname)
2930 : psprintf(
"col_%d", slot_idx)));
2933 new_rte->rtekind = RTE_SUBQUERY;
2934 new_rte->subquery = inner_queries[k];
2935 new_rte->alias = NULL;
2936 new_rte->eref = eref;
2937 new_rte->inFromCl =
true;
2938 new_rte->lateral =
false;
2939#if PG_VERSION_NUM < 160000
2940 new_rte->requiredPerms = 0;
2943 outer->rtable = lappend(outer->rtable, new_rte);
2944 comp_outer_rtindex[k] = (Index) list_length(outer->rtable);
2946 RangeTblRef *rtr = makeNode(RangeTblRef);
2947 rtr->rtindex = comp_outer_rtindex[k];
2948 outer->jointree->fromlist = lappend(outer->jointree->fromlist, rtr);
2960 (Node *) outer->targetList, &tctx);
2961 if (outer->jointree->quals)
2962 outer->jointree->quals =
2966 provsql_notice(
"safe-query multi-component rewrite bailed: a Var "
2967 "has no exposed column in its component's inner "
2969 pfree(inner_queries);
2976 provsql_notice(
"safe-query multi-component rewrite fired: split %d "
2977 "atoms into %d disconnected component%s",
2978 natoms, ncomp, ncomp == 1 ?
"" :
"s");
2980 pfree(inner_queries);
2982 pfree(inner_tlists);
2983 pfree(comp_inner_idx);
2984 pfree(atom_to_inner_idx);
2985 pfree(atom_to_inner_attno);
2986 pfree(comp_outer_rtindex);
3033 Node **residual_in_out) {
3034 int natoms = list_length(q->rtable);
3036 List *eq_pairs = NIL;
3042 bool *is_constant_class;
3043 Const **class_const_value;
3044 List *all_const_conjuncts = NIL;
3052 expression_tree_walker((Node *) q->targetList,
3054 if (*residual_in_out)
3055 expression_tree_walker(*residual_in_out,
3057 if (per_atom_quals != NULL) {
3059 for (j = 0; j < natoms; j++) {
3061 foreach (qlc, per_atom_quals[j])
3062 expression_tree_walker((Node *) lfirst(qlc),
3066 nvars = list_length(vctx.
vars);
3070 vars_arr = palloc(nvars *
sizeof(Var *));
3071 cls = palloc(nvars *
sizeof(
int));
3073 foreach (lc, vctx.
vars) {
3074 vars_arr[i] = (Var *) lfirst(lc);
3080 if (*residual_in_out)
3082 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
3084 int li, ri, ci, cj, k;
3085 lv = (Var *) lfirst(lc);
3087 rv = (Var *) lfirst(lc);
3090 if (li < 0 || ri < 0)
3096 for (k = 0; k < nvars; k++)
3103 is_constant_class = palloc0(nvars *
sizeof(
bool));
3104 class_const_value = palloc0(nvars *
sizeof(Const *));
3105 if (per_atom_quals != NULL) {
3107 for (j = 0; j < natoms; j++) {
3109 foreach (qlc, per_atom_quals[j])
3110 all_const_conjuncts = lappend(all_const_conjuncts, lfirst(qlc));
3113 if (*residual_in_out)
3118 foreach (qlc, all_const_conjuncts) {
3119 Expr *e = (Expr *) lfirst(qlc);
3129 if (!is_constant_class[root]) {
3130 is_constant_class[root] =
true;
3131 class_const_value[root] = k;
3135 list_free(all_const_conjuncts);
3139 if (per_atom_quals != NULL) {
3140 for (i = 0; i < nvars; i++) {
3142 Var *vp = vars_arr[i];
3143 Const *k = class_const_value[root];
3145 bool already =
false;
3151 if (!is_constant_class[root] || k == NULL)
3153 if (vp->varno < 1 || (
int) vp->varno > natoms)
3155 atom_idx = (int) vp->varno - 1;
3156 foreach (qlc, per_atom_quals[atom_idx]) {
3158 &v_existing, &k_existing)
3159 && v_existing->varno == vp->varno
3160 && v_existing->varattno == vp->varattno) {
3168 if (eqop == InvalidOid)
3170 new_op = (OpExpr *) makeNode(OpExpr);
3171 new_op->opno = eqop;
3172 new_op->opfuncid = InvalidOid;
3173 new_op->opresulttype = BOOLOID;
3174 new_op->opretset =
false;
3175 new_op->opcollid = InvalidOid;
3176 new_op->inputcollid = vp->varcollid;
3177 new_op->args = list_make2(copyObject(vp), copyObject(k));
3178 new_op->location = -1;
3179 per_atom_quals[atom_idx] =
3180 lappend(per_atom_quals[atom_idx], new_op);
3198 if (*residual_in_out != NULL) {
3199 List *conjuncts = NIL;
3203 foreach (qlc, conjuncts) {
3204 Node *cj = (Node *) lfirst(qlc);
3207 bool all_constant =
true;
3208 bool any_var =
false;
3210 foreach (vlc, cv.
vars) {
3211 Var *v = (Var *) lfirst(vlc);
3214 if (idx < 0 || !is_constant_class[cls[idx]]) {
3215 all_constant =
false;
3220 if (any_var && all_constant)
3222 kept = lappend(kept, cj);
3225 *residual_in_out = NULL;
3226 else if (list_length(kept) == 1)
3227 *residual_in_out = (Node *) linitial(kept);
3229 *residual_in_out = (Node *) makeBoolExpr(AND_EXPR, kept, -1);
3230 list_free(conjuncts);
3233 pfree(is_constant_class);
3234 pfree(class_const_value);
3339 int natoms = list_length(q->rtable);
3344 List *eq_pairs = NIL;
3365 foreach (lc, q->rtable) {
3366 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3368 if (rte->rtekind != RTE_RELATION)
3370 foreach (lc2, seen_relids) {
3371 if (lfirst_oid(lc2) == rte->relid) {
3378 seen_relids = lappend_oid(seen_relids, rte->relid);
3380 list_free(seen_relids);
3390 expression_tree_walker((Node *) q->targetList,
3392 if (q->jointree && q->jointree->quals)
3393 expression_tree_walker(q->jointree->quals,
3395 nvars = list_length(vctx.
vars);
3399 vars_arr = palloc(nvars *
sizeof(Var *));
3400 cls = palloc(nvars *
sizeof(
int));
3402 foreach (lc, vctx.
vars) {
3403 vars_arr[i] = (Var *) lfirst(lc);
3407 if (q->jointree && q->jointree->quals)
3409 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
3411 int li, ri, ci, cj, k;
3412 lv = (Var *) lfirst(lc);
3414 rv = (Var *) lfirst(lc);
3417 if (li < 0 || ri < 0)
3423 for (k = 0; k < nvars; k++)
3432 keeper = palloc(natoms *
sizeof(
int));
3433 for (j = 0; j < natoms; j++)
3436 any_unified =
false;
3437 for (j = 0; j < natoms; j++) {
3438 RangeTblEntry *rte_j;
3441 bool all_pairs_unify;
3443 ListCell *lc_a, *lc_b;
3446 rte_j = (RangeTblEntry *) list_nth(q->rtable, j);
3447 if (rte_j->rtekind != RTE_RELATION)
3452 group = list_make1_int(j);
3453 for (k = j + 1; k < natoms; k++) {
3454 RangeTblEntry *rte_k = (RangeTblEntry *) list_nth(q->rtable, k);
3455 if (rte_k->rtekind != RTE_RELATION)
3457 if (rte_k->relid != rte_j->relid)
3459 group = lappend_int(group, k);
3461 if (list_length(group) < 2) {
3472 all_pairs_unify =
true;
3473 foreach (lc_a, group) {
3474 int aa = lfirst_int(lc_a);
3475 foreach (lc_b, group) {
3476 int bb = lfirst_int(lc_b);
3477 bool this_pair_unifies =
false;
3481 for (ki = 0; ki < keys.
key_n; ki++) {
3483 bool all_pk_equated =
true;
3485 for (kc = 0; kc < key->
col_n; kc++) {
3486 AttrNumber attno = key->
cols[kc];
3491 if (idx_a < 0 || idx_b < 0 || cls[idx_a] != cls[idx_b]) {
3492 all_pk_equated =
false;
3496 if (all_pk_equated) {
3497 this_pair_unifies =
true;
3501 if (!this_pair_unifies) {
3502 all_pairs_unify =
false;
3506 if (!all_pairs_unify)
3510 if (all_pairs_unify) {
3511 foreach (lc_a, group) {
3512 int aa = lfirst_int(lc_a);
3533 old_to_new = palloc0((natoms + 1) *
sizeof(
int));
3535 for (j = 0; j < natoms; j++) {
3537 while (keeper[root] != root)
3538 root = keeper[root];
3540 old_to_new[j + 1] = new_idx++;
3542 for (j = 0; j < natoms; j++) {
3544 while (keeper[root] != root)
3545 root = keeper[root];
3547 old_to_new[j + 1] = old_to_new[root + 1];
3552 for (j = 0; j < natoms; j++) {
3554 while (keeper[root] != root)
3555 root = keeper[root];
3557 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
3558 new_rtable = lappend(new_rtable, copyObject(rte));
3569 seen_new = palloc0((new_idx + 1) *
sizeof(
bool));
3571 foreach (lc, q->jointree->fromlist) {
3572 Node *n = (Node *) lfirst(lc);
3573 if (IsA(n, RangeTblRef)) {
3574 RangeTblRef *rtr = (RangeTblRef *) n;
3575 int new_no = old_to_new[rtr->rtindex];
3579 if (seen_new[new_no])
3581 seen_new[new_no] =
true;
3582 clone = (RangeTblRef *) copyObject(rtr);
3583 clone->rtindex = new_no;
3584 new_fromlist = lappend(new_fromlist, clone);
3586 new_fromlist = lappend(new_fromlist, copyObject(n));
3596 new_q = (Query *) copyObject(q);
3597 new_q->rtable = new_rtable;
3598 if (new_q->jointree)
3599 new_q->jointree->fromlist = new_fromlist;
3600#if PG_VERSION_NUM >= 160000
3608 new_q->targetList = (List *)
3610 if (new_q->jointree && new_q->jointree->quals)
3611 new_q->jointree->quals =
4374 int natoms = list_length(q->rtable);
4380 bool has_self_join =
false;
4382 List *eq_pairs = NIL;
4388 int *class_atom_count;
4389 int root_class = -1;
4390 int *col_pos_of_class;
4401 if (q->setOperations || q->hasAggs || q->hasWindowFuncs || q->limitCount
4402 || q->limitOffset || q->groupingSets || q->hasDistinctOn
4403 || q->hasSubLinks || q->rtable == NIL)
4407 foreach (lc, q->jointree->fromlist)
4408 if (!IsA((Node *) lfirst(lc), RangeTblRef))
4425 atom_relid = palloc(natoms *
sizeof(Oid));
4426 atom_rank = palloc(natoms *
sizeof(
int));
4427 atom_det = palloc0(natoms *
sizeof(
bool));
4429 foreach (lc, q->rtable) {
4430 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4432 AttrNumber provsql_attno;
4433 bool has_provsql_col, has_meta;
4434 if (rte->rtekind != RTE_RELATION) {
4435 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4438 has_provsql_col = provsql_attno != InvalidAttrNumber
4439 && get_atttype(rte->relid, provsql_attno) == constants->
OID_TYPE_UUID;
4441 if (!has_provsql_col && !has_meta) {
4447 HeapTuple class_tup = SearchSysCache1(RELOID, ObjectIdGetDatum(rte->relid));
4448 bool ok_relkind =
false;
4449 if (HeapTupleIsValid(class_tup)) {
4451 ((Form_pg_class) GETSTRUCT(class_tup))->relkind == RELKIND_RELATION;
4452 ReleaseSysCache(class_tup);
4454 if (!ok_relkind || has_superclass(rte->relid)) {
4455 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4458 atom_relid[i] = InvalidOid;
4466 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4468 atom_relid[i] = rte->relid;
4472 for (j = 0; j < i; j++)
4473 if (!atom_det[j] && atom_relid[j] == rte->relid) {
4474 atom_rank[i] = atom_rank[j]; has_self_join =
true;
break;
4476 if (atom_rank[i] < 0) atom_rank[i] = nranks++;
4480 if (n_tracked < 1) {
4481 pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL;
4490 (void) has_self_join;
4494 if (q->jointree && q->jointree->quals)
4496 nvars = list_length(vctx.
vars);
4497 if (nvars == 0) { pfree(atom_relid); pfree(atom_rank); pfree(atom_det);
return NULL; }
4499 vars_arr = palloc(nvars *
sizeof(Var *));
4500 cls = palloc(nvars *
sizeof(
int));
4502 foreach (lc, vctx.
vars) { vars_arr[i] = (Var *) lfirst(lc); cls[i] = i; i++; }
4504 if (q->jointree && q->jointree->quals)
4506 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
4507 Var *lv = (Var *) lfirst(lc);
int li, ri, ci, cj, k;
4510 Var *rv = (Var *) lfirst(lc);
4514 if (li < 0 || ri < 0)
continue;
4515 ci = cls[li]; cj = cls[ri];
4516 if (ci == cj)
continue;
4517 for (k = 0; k < nvars; k++)
if (cls[k] == cj) cls[k] = ci;
4521 class_compact = palloc(nvars *
sizeof(
int));
4522 for (i = 0; i < nvars; i++) class_compact[i] = -1;
4523 for (i = 0; i < nvars; i++) {
4525 if (class_compact[r] < 0) class_compact[r] = nclasses++;
4527#define CCLASS(varidx) (class_compact[cls[(varidx)]])
4530 class_atom_count = palloc0(nclasses *
sizeof(
int));
4532 int *seen = palloc0((
size_t) nclasses * (
size_t) natoms *
sizeof(
int));
4533 for (i = 0; i < nvars; i++) {
4535 Index vno = vars_arr[i]->varno;
4537 if (vno < 1 || (
int) vno > natoms)
continue;
4539 if (atom_det[a])
continue;
4540 if (!seen[c * natoms + a]) { seen[c * natoms + a] = 1; class_atom_count[c]++; }
4546 for (i = 0; i < nclasses; i++)
4547 if (class_atom_count[i] == n_tracked) { root_class = i;
break; }
4548 if (root_class < 0) {
4550 provsql_notice(
"not inversion-free: no root variable (non-hierarchical)");
4557 col_pos_of_class = palloc0((
size_t) nranks * (
size_t) nclasses *
sizeof(
int));
4558 for (i = 0; i < nvars; i++) {
4560 Index vno = vars_arr[i]->varno;
4562 if (vno < 1 || (
int) vno > natoms)
continue;
4564 if (atom_det[a])
continue;
4565 rrank = atom_rank[a];
4566 pos = (int) vars_arr[i]->varattno;
4567 if (col_pos_of_class[rrank * nclasses + c] == 0)
4568 col_pos_of_class[rrank * nclasses + c] = pos;
4569 else if (col_pos_of_class[rrank * nclasses + c] != pos) {
4571 provsql_notice(
"not inversion-free: class at inconsistent column "
4572 "positions within one relation (inversion / self-equality)");
4580 prec = palloc0((
size_t) nclasses * (
size_t) nclasses *
sizeof(
int));
4581 for (i = 0; i < nvars; i++) {
4583 int posi = (int) vars_arr[i]->varattno;
4584 Index vno = vars_arr[i]->varno;
4585 if (vno >= 1 && (
int) vno <= natoms && atom_det[vno - 1])
4587 for (j = 0; j < nvars; j++) {
4589 if (vars_arr[j]->varno != vno)
continue;
4591 posj = (int) vars_arr[j]->varattno;
4592 if (posi < posj) prec[ci * nclasses + cj] = 1;
4593 else if (posi == posj && ci != cj) prec[ci * nclasses + cj] = 1;
4597 indeg = palloc0(nclasses *
sizeof(
int));
4598 for (i = 0; i < nclasses; i++)
4599 for (j = 0; j < nclasses; j++)
4600 if (i != j && prec[i * nclasses + j]) indeg[j]++;
4601 topo = palloc(nclasses *
sizeof(
int));
4603 bool *done = palloc0(nclasses *
sizeof(
bool));
4608 if (!done[root_class] && indeg[root_class] == 0) picked = root_class;
4609 for (i = 0; picked < 0 && i < nclasses; i++)
4610 if (!done[i] && indeg[i] == 0) picked = i;
4612 done[picked] =
true; topo[ntopo++] = picked;
4613 for (j = 0; j < nclasses; j++)
4614 if (!done[j] && prec[picked * nclasses + j]) indeg[j]--;
4616 }
while (picked >= 0);
4619 if (ntopo != nclasses) {
4622 "(inversion, e.g. symmetric closure R(x,y),R(y,x))");
4636 for (i = 0; i < nvars; i++) {
4637 int pos = (int) vars_arr[i]->varattno;
4642 for (i = 0; i < nvars; i++) {
4643 Index vno = vars_arr[i]->varno;
4645 if (vno < 1 || (
int) vno > natoms)
continue;
4647 if (atom_det[a])
continue;
4648 pos = (int) vars_arr[i]->varattno;