809 Query *q, Node *quals,
812 List *eq_pairs = NIL;
817 int natoms = list_length(q->rtable);
818 int *class_atom_count;
819 int *class_atom_anchor_attno;
821 List *atoms_out = NIL;
822 int *atom_group = NULL;
823 bool *in_targetlist = NULL;
824 int *first_member_of_group = NULL;
825 int *group_singleton_counter = NULL;
826 bool have_partial_class =
false;
827 int partial_first = -1;
828 Bitmapset *bridging_classes = NULL;
842 bool *determined_in = NULL;
843 int *class_atom_count_fd = NULL;
844 bool fd_aware_mode =
false;
845 int *atom_anchor_class = NULL;
863 expression_tree_walker((Node *) q->targetList,
868 nvars = list_length(vctx.
vars);
872 vars_arr = palloc(nvars *
sizeof(Var *));
873 cls = palloc(nvars *
sizeof(
int));
875 foreach (lc, vctx.
vars) {
876 vars_arr[i] = (Var *) lfirst(lc);
889 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
891 int li, ri, ci, cj, k;
892 lv = (Var *) lfirst(lc);
894 rv = (Var *) lfirst(lc);
897 if (li < 0 || ri < 0)
903 for (k = 0; k < nvars; k++)
910 class_atom_count = palloc0(nvars *
sizeof(
int));
911 class_atom_anchor_attno =
912 palloc0((
size_t) nvars * (
size_t) natoms *
sizeof(
int));
914#define ANCHOR(c, atom_idx) class_atom_anchor_attno[(c) * natoms + (atom_idx)]
916 for (i = 0; i < nvars; i++) {
919 varno = vars_arr[i]->varno;
920 if (varno < 1 || (
int) varno > natoms)
922 atom_idx = (int) varno - 1;
923 if (
ANCHOR(c, atom_idx) == 0) {
924 class_atom_count[c]++;
925 ANCHOR(c, atom_idx) = vars_arr[i]->varattno;
926 }
else if (
ANCHOR(c, atom_idx) != vars_arr[i]->varattno) {
931 class_atom_count[c] = natoms + 1;
956 palloc0((
size_t) nvars * (
size_t) natoms *
sizeof(
bool));
957#define DETERMINED(c, atom_idx) determined_in[(c) * natoms + (atom_idx)]
959 for (j = 0; j < natoms; j++) {
960 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
963 if (rte->rtekind != RTE_RELATION)
967 for (ki = 0; ki < keys.
key_n; ki++) {
969 bool all_anchored =
true;
982 for (kc = 0; kc < key->
col_n; kc++) {
987 all_anchored =
false;
990 if (class_atom_count[cls[idx]] < 2
991 || class_atom_count[cls[idx]] > natoms) {
992 all_anchored =
false;
1000 for (vi = 0; vi < nvars; vi++) {
1001 Var *vp = vars_arr[vi];
1002 bool is_key_col =
false;
1003 if (vp->varno != (Index) (j + 1))
1005 for (kc = 0; kc < key->
col_n; kc++) {
1006 if (vp->varattno == key->
cols[kc]) {
1063 for (j = 0; j < natoms; j++) {
1064 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
1065 AttrNumber provsql_attno;
1066 bool has_provsql_col;
1068 HeapTuple class_tup;
1069 Form_pg_class classform;
1071 if (rte->rtekind != RTE_RELATION)
1075 provsql_attno != InvalidAttrNumber
1076 && get_atttype(rte->relid, provsql_attno) == constants->
OID_TYPE_UUID;
1078 if (has_provsql_col || has_meta)
1082 SearchSysCache1(RELOID, ObjectIdGetDatum(rte->relid));
1083 if (!HeapTupleIsValid(class_tup))
1085 classform = (Form_pg_class) GETSTRUCT(class_tup);
1086 ok_relkind = (classform->relkind == RELKIND_RELATION);
1087 ReleaseSysCache(class_tup);
1091 if (has_superclass(rte->relid))
1098 for (i = 0; i < nvars; i++) {
1109 class_atom_count_fd = palloc0(nvars *
sizeof(
int));
1110 for (i = 0; i < nvars; i++) {
1114 if (class_atom_count[i] > natoms)
1117 for (j = 0; j < natoms; j++) {
1119 class_atom_count_fd[c]++;
1128 in_targetlist = palloc0(nvars *
sizeof(
bool));
1132 expression_tree_walker((Node *) q->targetList,
1134 foreach (tlc, tlist_ctx.
vars) {
1135 Var *v = (Var *) lfirst(tlc);
1138 in_targetlist[idx] =
true;
1145 for (i = 0; i < nvars; i++) {
1148 if (class_atom_count[i] == natoms) {
1191 if (root_class < 0) {
1192 bool eligible =
true;
1194 for (i = 0; i < nvars && eligible; i++) {
1197 if (class_atom_count[i] > natoms) {
1203 bool *atom_covered = palloc0(natoms *
sizeof(
bool));
1204 for (i = 0; i < nvars; i++) {
1206 Index vn = vars_arr[i]->varno;
1207 if (vn < 1 || (
int) vn > natoms)
1209 if (class_atom_count[c] > natoms)
1211 atom_covered[vn - 1] =
true;
1213 for (j = 0; j < natoms; j++) {
1214 if (!atom_covered[j]) {
1219 pfree(atom_covered);
1225 Bitmapset **atoms_fd = palloc0(nvars *
sizeof(Bitmapset *));
1226 int *class_reprs = palloc(nvars *
sizeof(
int));
1228 for (i = 0; i < nvars && eligible; i++) {
1231 if (class_atom_count[i] > natoms)
1233 if (class_atom_count[i] < 2)
1235 for (j = 0; j < natoms; j++) {
1237 atoms_fd[i] = bms_add_member(atoms_fd[i], j);
1239 class_reprs[nreprs++] = i;
1241 for (i = 0; i < nreprs && eligible; i++) {
1243 for (k = i + 1; k < nreprs && eligible; k++) {
1244 Bitmapset *a = atoms_fd[class_reprs[i]];
1245 Bitmapset *b = atoms_fd[class_reprs[k]];
1246 bool nested = bms_is_subset(a, b) || bms_is_subset(b, a);
1247 bool disjoint = !bms_overlap(a, b);
1248 if (!nested && !disjoint) {
1254 for (i = 0; i < nvars; i++)
1256 bms_free(atoms_fd[i]);
1278 atom_anchor_class = palloc(natoms *
sizeof(
int));
1279 for (j = 0; j < natoms; j++)
1280 atom_anchor_class[j] = -1;
1281 for (i = 0; i < nvars; i++) {
1285 if (class_atom_count[i] > natoms)
1287 if (class_atom_count[i] < 2)
1290 for (j = 0; j < natoms; j++) {
1292 && atom_anchor_class[j] < 0)
1293 atom_anchor_class[j] = c;
1296 for (j = 0; j < natoms; j++) {
1297 if (atom_anchor_class[j] >= 0)
1299 for (i = 0; i < nvars; i++) {
1302 if (class_atom_count[i] < 2 || class_atom_count[i] > natoms)
1305 atom_anchor_class[j] = i;
1314 for (j = 0; j < natoms; j++) {
1315 if (atom_anchor_class[j] < 0) {
1322 fd_aware_mode =
true;
1354 atom_group = palloc(natoms *
sizeof(
int));
1355 for (j = 0; j < natoms; j++)
1364 goto skip_partial_coverage;
1367 Bitmapset **sig = palloc0(natoms *
sizeof(Bitmapset *));
1368 bool has_outer_atom =
true;
1370 for (i = 0; i < nvars; i++) {
1374 if (class_atom_count[c] < 2)
1376 if (class_atom_count[c] > natoms)
1378 if (class_atom_count[c] == natoms)
1380 have_partial_class =
true;
1381 if (partial_first < 0)
1383 for (j = 0; j < natoms; j++) {
1385 sig[j] = bms_add_member(sig[j], c);
1389 if (have_partial_class) {
1390 has_outer_atom =
false;
1391 for (j = 0; j < natoms; j++) {
1392 if (bms_is_empty(sig[j])) {
1393 has_outer_atom =
true;
1399 if (have_partial_class && has_outer_atom) {
1402 for (j = 0; j < natoms; j++)
1403 atom_group[j] = bms_is_empty(sig[j]) ? -1 : 0;
1404 }
else if (have_partial_class) {
1418 Bitmapset **group_sigs;
1424 group_sigs = palloc0(natoms *
sizeof(Bitmapset *));
1425 for (j = 0; j < natoms; j++) {
1427 for (g = 0; g < ngroups; g++) {
1428 if (bms_equal(group_sigs[g], sig[j])) {
1435 atom_group[j] = ngroups;
1436 group_sigs[ngroups] = sig[j];
1444 for (i = 0; i < nvars; i++) {
1446 Bitmapset *touched_groups = NULL;
1450 if (class_atom_count[c] < 2 || class_atom_count[c] >= natoms)
1452 for (jj = 0; jj < natoms; jj++) {
1454 touched_groups = bms_add_member(touched_groups,
1457 if (bms_num_members(touched_groups) > 1)
1458 bridging_classes = bms_add_member(bridging_classes, c);
1459 bms_free(touched_groups);
1465 if (!bms_is_empty(bridging_classes)) {
1466 int *parent = palloc(ngroups *
sizeof(
int));
1467 int *super = palloc(ngroups *
sizeof(
int));
1471 for (g = 0; g < ngroups; g++) {
1477 while ((c = bms_next_member(bridging_classes, c)) >= 0) {
1480 for (jj = 0; jj < natoms; jj++) {
1484 gj = atom_group[jj];
1491 while (parent[ra] != ra) ra = parent[ra];
1493 while (parent[rb] != rb) rb = parent[rb];
1499 for (g = 0; g < ngroups; g++) {
1501 while (parent[r] != r) r = parent[r];
1503 super[r] = next_super++;
1504 super[g] = super[r];
1507 for (j = 0; j < natoms; j++) {
1508 if (atom_group[j] >= 0)
1509 atom_group[j] = super[atom_group[j]];
1514 bms_free(bridging_classes);
1515 bridging_classes = NULL;
1519 for (j = 0; j < natoms; j++) bms_free(sig[j]);
1523skip_partial_coverage:
1534 int g, ngroups_local = 0;
1535 for (j = 0; j < natoms; j++)
1536 if (atom_group[j] >= 0 && atom_group[j] + 1 > ngroups_local)
1537 ngroups_local = atom_group[j] + 1;
1538 first_member_of_group = palloc(natoms *
sizeof(
int));
1539 group_singleton_counter = palloc(natoms *
sizeof(
int));
1540 for (g = 0; g < ngroups_local; g++) {
1541 first_member_of_group[g] = -1;
1542 group_singleton_counter[g] = 0;
1544 for (j = 0; j < natoms; j++) {
1545 int g_loc = atom_group[j];
1546 if (g_loc >= 0 && first_member_of_group[g_loc] < 0)
1547 first_member_of_group[g_loc] = j;
1566 for (i = 0; i < nvars; i++) {
1568 int atom_idx = (int) vars_arr[i]->varno - 1;
1569 if (fd_aware_mode) {
1570 if (class_atom_count[c] >= 2 && class_atom_count[c] <= natoms)
1572 if (class_atom_count[c] == 1 && in_targetlist[i])
1575 provsql_notice(
"safe-query rewriter (fd-aware): Var (varno=%u, varattno=%d) "
1576 "belongs to a class with no outer slot",
1577 (
unsigned) vars_arr[i]->varno,
1578 (
int) vars_arr[i]->varattno);
1582 if (class_atom_count[c] == natoms)
1584 if (class_atom_count[c] >= 2 && class_atom_count[c] < natoms
1585 && atom_group[atom_idx] >= 0)
1594 if (class_atom_count[c] == 1 && in_targetlist[i])
1597 provsql_notice(
"safe-query rewriter: Var (varno=%u, varattno=%d) "
1598 "belongs to a class that does not match any outer or "
1599 "inner-group slot -- rewrite scope does not yet cover "
1601 (
unsigned) vars_arr[i]->varno,
1602 (
int) vars_arr[i]->varattno);
1621 for (j = 0; j < natoms; j++) {
1624 int local_root = fd_aware_mode ? atom_anchor_class[j] : root_class;
1626 sa->
rtindex = (Index) (j + 1);
1642 for (i = 0; i < nvars; i++) {
1644 if (cls[i] != i || i == local_root)
1646 if (fd_aware_mode) {
1652 if (class_atom_count[i] < 2 || class_atom_count[i] > natoms)
1654 }
else if (class_atom_count[i] != natoms) {
1675 for (i = 0; i < nvars; i++) {
1678 bool already_have =
false;
1679 bool is_first_member;
1680 if (!in_targetlist[i])
1682 if (class_atom_count[cls[i]] != 1)
1684 if ((
int) vars_arr[i]->varno - 1 != j)
1688 if (ex->
base_attno == vars_arr[i]->varattno) {
1689 already_have =
true;
1698 is_first_member = (sa->
group_id >= 0
1699 && first_member_of_group[sa->
group_id] == j);
1700 if (sa->
group_id < 0 || is_first_member) {
1702 (AttrNumber) (list_length(sa->
proj_slots) + 1);
1704 group_singleton_counter[sa->
group_id]++;
1706 (AttrNumber) group_singleton_counter[sa->
group_id];
1714 && first_member_of_group[sa->
group_id] == j) {
1715 group_singleton_counter[sa->
group_id] =
1730 RangeTblEntry *rte =
1731 (RangeTblEntry *) list_nth(q->rtable, j);
1738 "has an empty block_key (whole table is one "
1739 "block); the wrap's DISTINCT could split the "
1740 "block across multiple output rows, deferred",
1759 "has block_key column attno=%d outside the "
1760 "projection slots; the wrap would split a "
1770 atoms_out = lappend(atoms_out, sa);
1779 if (have_partial_class) {
1784 foreach (alc, atoms_out) {
1790 for (g = 0; g <= max_gid; g++) {
1797 foreach (alc, atoms_out) {
1819 for (g = 0; g <= max_gid; g++) {
1820 for (i = 0; i < nvars; i++) {
1823 AttrNumber first_attno = 0;
1824 Oid first_type = InvalidOid;
1825 int32 first_typmod = -1;
1826 Oid first_coll = InvalidOid;
1830 if (class_atom_count[c] != natoms)
1832 foreach (mlc, arr[g]->member_atoms) {
1834 int atom_idx = (int) m->
rtindex - 1;
1835 AttrNumber attno =
ANCHOR(c, atom_idx);
1838 Form_pg_attribute attform;
1839 Oid mtype, mcoll, eqop, eqfunc;
1845 rte = (RangeTblEntry *) list_nth(q->rtable, atom_idx);
1846 atttup = SearchSysCache2(ATTNUM,
1847 ObjectIdGetDatum(rte->relid),
1848 Int16GetDatum(attno));
1849 if (!HeapTupleIsValid(atttup))
1851 attform = (Form_pg_attribute) GETSTRUCT(atttup);
1852 mtype = attform->atttypid;
1853 mtypmod = attform->atttypmod;
1854 mcoll = attform->attcollation;
1855 ReleaseSysCache(atttup);
1856 if (first_touching == NULL) {
1858 first_attno = attno;
1860 first_typmod = mtypmod;
1865 if (!OidIsValid(eqop))
1867 eqfunc = get_opcode(eqop);
1868 if (!OidIsValid(eqfunc))
1870 lv = makeVar(first_touching->
rtindex, first_attno,
1871 first_type, first_typmod, first_coll, 0);
1872 rv = makeVar(m->
rtindex, attno, mtype, mtypmod, mcoll, 0);
1873 eq = makeNode(OpExpr);
1875 eq->opfuncid = eqfunc;
1876 eq->opresulttype = BOOLOID;
1877 eq->opretset =
false;
1878 eq->opcollid = InvalidOid;
1879 eq->inputcollid = first_coll;
1880 eq->args = list_make2(lv, rv);
1883 lappend(arr[g]->inner_quals, eq);
1888 for (g = 0; g <= max_gid; g++)
1889 *groups_out = lappend(*groups_out, arr[g]);
1896 pfree(class_atom_count);
1897 pfree(class_atom_anchor_attno);
1902 pfree(in_targetlist);
1903 if (first_member_of_group)
1904 pfree(first_member_of_group);
1905 if (group_singleton_counter)
1906 pfree(group_singleton_counter);
1908 pfree(determined_in);
1909 if (class_atom_count_fd)
1910 pfree(class_atom_count_fd);
1911 if (atom_anchor_class)
1912 pfree(atom_anchor_class);
1917 pfree(class_atom_count);
1918 pfree(class_atom_anchor_attno);
1924 pfree(in_targetlist);
1925 if (first_member_of_group)
1926 pfree(first_member_of_group);
1927 if (group_singleton_counter)
1928 pfree(group_singleton_counter);
1930 pfree(determined_in);
1931 if (class_atom_count_fd)
1932 pfree(class_atom_count_fd);
1933 if (atom_anchor_class)
1934 pfree(atom_anchor_class);
2049 RangeTblEntry *base_rte,
2051 Index outer_rtindex,
2052 List *pushed_quals) {
2053 Query *inner = makeNode(Query);
2054 RangeTblRef *rtr = makeNode(RangeTblRef);
2055 FromExpr *jt = makeNode(FromExpr);
2056 RangeTblEntry *inner_rte;
2060 inner_rte = copyObject(base_rte);
2062 inner->commandType = CMD_SELECT;
2063 inner->canSetTag =
false;
2064 inner->rtable = list_make1(inner_rte);
2065#if PG_VERSION_NUM >= 160000
2071 if (base_rte->perminfoindex != 0
2072 && outer_src && outer_src->rteperminfos != NIL
2073 && (
int) base_rte->perminfoindex <= list_length(outer_src->rteperminfos)) {
2074 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2075 outer_src->rteperminfos,
2076 base_rte->perminfoindex - 1);
2077 inner->rteperminfos = list_make1(copyObject(rpi));
2078 inner_rte->perminfoindex = 1;
2080 inner->rteperminfos = NIL;
2081 inner_rte->perminfoindex = 0;
2085 jt->fromlist = list_make1(rtr);
2087 inner->jointree = jt;
2089 inner->targetList = NIL;
2090 inner->distinctClause = NIL;
2091 inner->hasDistinctOn =
false;
2093 foreach (lc, proj_slots) {
2096 Form_pg_attribute attform;
2101 TargetEntry *te = makeNode(TargetEntry);
2102 SortGroupClause *sgc = makeNode(SortGroupClause);
2104 atttup = SearchSysCache2(ATTNUM,
2105 ObjectIdGetDatum(base_rte->relid),
2107 if (!HeapTupleIsValid(atttup))
2108 provsql_error(
"safe-query rewriter: cannot resolve attno %d of "
2110 (
int) slot->
base_attno, (
unsigned) base_rte->relid);
2111 attform = (Form_pg_attribute) GETSTRUCT(atttup);
2112 atttypid = attform->atttypid;
2113 atttypmod = attform->atttypmod;
2114 attcollation = attform->attcollation;
2115 ReleaseSysCache(atttup);
2118 v = makeVar(1, slot->
base_attno, atttypid, atttypmod, attcollation, 0);
2119 te->expr = (Expr *) v;
2120 te->resno = (AttrNumber) slot_idx;
2121 te->resname = psprintf(
"provsql_slot_%d", slot_idx);
2122 te->ressortgroupref = (Index) slot_idx;
2123 te->resorigtbl = base_rte->relid;
2125 te->resjunk =
false;
2126 inner->targetList = lappend(inner->targetList, te);
2128 sgc->tleSortGroupRef = (Index) slot_idx;
2129 get_sort_group_operators(atttypid,
true,
true,
false,
2130 &sgc->sortop, &sgc->eqop, NULL, &sgc->hashable);
2131 sgc->nulls_first =
false;
2132 inner->distinctClause = lappend(inner->distinctClause, sgc);
2140 if (pushed_quals != NIL) {
2142 List *remapped = NIL;
2145 foreach (qlc, pushed_quals) {
2146 Node *q = (Node *) copyObject(lfirst(qlc));
2148 remapped = lappend(remapped, q);
2150 if (list_length(remapped) == 1)
2151 inner->jointree->quals = (Node *) linitial(remapped);
2153 inner->jointree->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2220 Query *inner = makeNode(Query);
2221 FromExpr *jt = makeNode(FromExpr);
2223 RangeTblEntry *first_rte;
2225 Form_pg_attribute attform;
2232 int natoms = list_length(atoms);
2234 inner->commandType = CMD_SELECT;
2235 inner->canSetTag =
false;
2236 inner->rtable = NIL;
2237 inner->jointree = jt;
2240#if PG_VERSION_NUM >= 160000
2241 inner->rteperminfos = NIL;
2253 RangeTblEntry *src_rte =
2254 (RangeTblEntry *) list_nth(outer_src->rtable, (
int) sa->
rtindex - 1);
2255 RangeTblEntry *cloned = (RangeTblEntry *) copyObject(src_rte);
2256 RangeTblRef *rtr = makeNode(RangeTblRef);
2262#if PG_VERSION_NUM >= 160000
2263 if (cloned->perminfoindex != 0
2264 && outer_src->rteperminfos != NIL
2265 && (
int) cloned->perminfoindex
2266 <= list_length(outer_src->rteperminfos)) {
2267 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2268 outer_src->rteperminfos,
2269 cloned->perminfoindex - 1);
2270 inner->rteperminfos =
2271 lappend(inner->rteperminfos, copyObject(rpi));
2272 cloned->perminfoindex = (Index) list_length(inner->rteperminfos);
2274 cloned->perminfoindex = 0;
2278 inner->rtable = lappend(inner->rtable, cloned);
2279 rtr->rtindex = inner_idx;
2280 jt->fromlist = lappend(jt->fromlist, rtr);
2290 List *all_quals = NIL;
2292 all_quals = lappend(all_quals,
2293 copyObject((Node *) lfirst(lc)));
2298 all_quals = lappend(all_quals,
2299 copyObject((Node *) lfirst(qlc)));
2303 List *remapped = NIL;
2304 foreach (qlc, all_quals) {
2305 Node *qq = (Node *) lfirst(qlc);
2307 remapped = lappend(remapped, qq);
2309 if (remapped == NIL)
2311 else if (list_length(remapped) == 1)
2312 jt->quals = (Node *) linitial(remapped);
2314 jt->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2325 first_rte = (RangeTblEntry *)
2326 list_nth(outer_src->rtable, (
int) first_member->
rtindex - 1);
2328 inner->targetList = NIL;
2329 inner->groupClause = NIL;
2338 Bitmapset *emitted = NULL;
2342 RangeTblEntry *m_rte = (RangeTblEntry *)
2343 list_nth(outer_src->rtable, (
int) m->
rtindex - 1);
2348 SortGroupClause *sgc;
2350 if (bms_is_member((
int) slot->
outer_attno, emitted))
2352 emitted = bms_add_member(emitted, (
int) slot->
outer_attno);
2354 atttup = SearchSysCache2(ATTNUM,
2355 ObjectIdGetDatum(m_rte->relid),
2357 if (!HeapTupleIsValid(atttup))
2358 provsql_error(
"safe-query rewriter: cannot resolve attno %d of "
2359 "relation %u in inner sub-Query",
2360 (
int) slot->
base_attno, (
unsigned) m_rte->relid);
2361 attform = (Form_pg_attribute) GETSTRUCT(atttup);
2362 atttypid = attform->atttypid;
2363 atttypmod = attform->atttypmod;
2364 attcollation = attform->attcollation;
2365 ReleaseSysCache(atttup);
2367 te = makeNode(TargetEntry);
2368 sgc = makeNode(SortGroupClause);
2371 atttypid, atttypmod, attcollation, 0);
2372 te->expr = (Expr *) cv;
2374 te->resname = psprintf(
"provsql_slot_%d",
2377 te->resorigtbl = m_rte->relid;
2379 te->resjunk =
false;
2380 inner->targetList = lappend(inner->targetList, te);
2383 get_sort_group_operators(atttypid,
true,
true,
false,
2384 &sgc->sortop, &sgc->eqop, NULL,
2386 sgc->nulls_first =
false;
2387 inner->groupClause = lappend(inner->groupClause, sgc);
2393 (void) first_member; (void) first_rte;
2420 Query *q, List *atoms, List *groups,
2422 Query *outer = copyObject(q);
2424 List *new_rtable = NIL;
2425#if PG_VERSION_NUM >= 160000
2426 List *new_rteperminfos = NIL;
2428 List *new_fromlist = NIL;
2432 int ngroups = list_length(groups);
2433 bool *group_emitted = NULL;
2434 int total_atoms_in_groups = 0;
2440 group_emitted = palloc0(ngroups *
sizeof(
bool));
2441 foreach (lc, groups) {
2443 total_atoms_in_groups += list_length(gr->
member_atoms);
2451 if (outer->jointree)
2452 outer->jointree->quals =
2453 residual ? (Node *) copyObject(residual) : NULL;
2459 foreach (lc, outer->rtable) {
2460 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2467 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2468 Alias *eref = makeNode(Alias);
2472 eref->aliasname = rte->eref && rte->eref->aliasname
2473 ? pstrdup(rte->eref->aliasname)
2474 : pstrdup(
"provsql_wrap");
2475 eref->colnames = NIL;
2477 (void) lfirst(slot_lc);
2479 eref->colnames = lappend(eref->colnames,
2480 makeString(psprintf(
"provsql_slot_%d",
2484 new_rte->rtekind = RTE_SUBQUERY;
2485 new_rte->subquery = inner;
2486 new_rte->alias = NULL;
2487 new_rte->eref = eref;
2488 new_rte->inFromCl = rte->inFromCl;
2489 new_rte->lateral =
false;
2490#if PG_VERSION_NUM < 160000
2491 new_rte->requiredPerms = 0;
2496 new_rtable = lappend(new_rtable, new_rte);
2497 rtr = makeNode(RangeTblRef);
2498 rtr->rtindex = outer_pos;
2499 new_fromlist = lappend(new_fromlist, rtr);
2504 if (!group_emitted[g]) {
2506 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
2507 Alias *eref = makeNode(Alias);
2509 int total_inner_cols = inner->targetList != NIL
2510 ? list_length(inner->targetList) : 0;
2512 eref->aliasname = pstrdup(
"provsql_group");
2513 eref->colnames = NIL;
2514 for (slot_idx = 1; slot_idx <= total_inner_cols; slot_idx++) {
2515 eref->colnames = lappend(eref->colnames,
2516 makeString(psprintf(
"provsql_slot_%d",
2520 new_rte->rtekind = RTE_SUBQUERY;
2521 new_rte->subquery = inner;
2522 new_rte->alias = NULL;
2523 new_rte->eref = eref;
2524 new_rte->inFromCl = rte->inFromCl;
2525 new_rte->lateral =
false;
2526#if PG_VERSION_NUM < 160000
2527 new_rte->requiredPerms = 0;
2532 new_rtable = lappend(new_rtable, new_rte);
2533 rtr = makeNode(RangeTblRef);
2534 rtr->rtindex = outer_pos;
2535 new_fromlist = lappend(new_fromlist, rtr);
2536 group_emitted[g] =
true;
2544 outer->rtable = new_rtable;
2545 if (outer->jointree)
2546 outer->jointree->fromlist = new_fromlist;
2547#if PG_VERSION_NUM >= 160000
2551 outer->rteperminfos = new_rteperminfos;
2567 outer->targetList = (List *)
2569 if (outer->jointree && outer->jointree->quals)
2570 outer->jointree->quals =
2574 pfree(group_emitted);
2583 provsql_notice(
"safe-query rewrite bailed: a Var has no projection "
2584 "slot in its (grouped or outer-wrap) atom");
2590 int total_slots = 0;
2591 int total_pushed = 0;
2592 int has_col_push = 0;
2593 foreach (lc, atoms) {
2600 initStringInfo(&buf);
2601 appendStringInfo(&buf,
2602 "safe-query rewrite fired: wrapped %d atoms with "
2603 "SELECT DISTINCT on %d total slot(s)",
2604 list_length(atoms) - total_atoms_in_groups,
2607 appendStringInfo(&buf,
2608 ", folded %d atom%s into %d inner sub-Quer%s",
2609 total_atoms_in_groups,
2610 total_atoms_in_groups == 1 ?
"" :
"s",
2611 ninner, ninner == 1 ?
"y" :
"ies");
2613 if (has_col_push || total_pushed > 0) {
2614 const char *sep =
" (";
2616 appendStringInfoString(&buf, sep);
2617 appendStringInfoString(&buf,
"column pushdown");
2620 if (total_pushed > 0) {
2621 appendStringInfoString(&buf, sep);
2622 appendStringInfo(&buf,
"%d atom-local qual%s pushed",
2623 total_pushed, total_pushed == 1 ?
"" :
"s");
2625 appendStringInfoChar(&buf,
')');
2781 List **per_atom_quals,
2785 int natoms = list_length(q->rtable);
2786 Query **inner_queries;
2788 List **inner_tlists;
2789 int *comp_inner_idx;
2790 int *atom_to_inner_idx;
2791 int *atom_to_inner_attno;
2792 Index *comp_outer_rtindex;
2795 List *conjuncts = NIL;
2796 List *outer_resid = NIL;
2801 inner_quals = palloc0(ncomp *
sizeof(List *));
2802 inner_tlists = palloc0(ncomp *
sizeof(List *));
2803 comp_inner_idx = palloc0(ncomp *
sizeof(
int));
2804 atom_to_inner_idx = palloc0(natoms *
sizeof(
int));
2805 atom_to_inner_attno = palloc0(natoms *
sizeof(
int));
2806 comp_outer_rtindex = palloc0(ncomp *
sizeof(Index));
2809 for (j = 0; j < natoms; j++) {
2810 int c = atom_to_comp[j];
2811 comp_inner_idx[c]++;
2812 atom_to_inner_idx[j] = comp_inner_idx[c];
2820 foreach (lc, q->targetList) {
2821 TargetEntry *te = (TargetEntry *) lfirst(lc);
2826 if (bms_is_empty(vctx.
varnos)) {
2834 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2836 if (v < 1 || v > natoms) {
2840 c = atom_to_comp[v - 1];
2843 else if (chosen != c) {
2849 inner_tlists[chosen] = lappend(inner_tlists[chosen], te);
2860 for (k = 0; k < ncomp; k++) {
2861 if (inner_tlists[k] == NIL) {
2862 TargetEntry *anchor = makeNode(TargetEntry);
2863 anchor->expr = (Expr *) makeConst(INT4OID, -1, InvalidOid,
2865 Int32GetDatum(1),
false,
true);
2867 anchor->resname = pstrdup(
"provsql_anchor");
2868 anchor->ressortgroupref = 1;
2869 anchor->resjunk =
false;
2870 inner_tlists[k] = list_make1(anchor);
2879 foreach (lc, conjuncts) {
2880 Node *qual = (Node *) lfirst(lc);
2884 bool keep_outer =
false;
2887 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
2889 if (v < 1 || v > natoms) {
2893 c = atom_to_comp[v - 1];
2896 else if (chosen != c) {
2902 if (keep_outer || chosen < 0)
2903 outer_resid = lappend(outer_resid, qual);
2905 inner_quals[chosen] = lappend(inner_quals[chosen], qual);
2909 inner_queries = palloc0(ncomp *
sizeof(Query *));
2910 for (k = 0; k < ncomp; k++) {
2911 Query *inner = makeNode(Query);
2912 FromExpr *jt = makeNode(FromExpr);
2913 int inner_attno = 0;
2917 inner->commandType = CMD_SELECT;
2918 inner->canSetTag =
false;
2919 inner->rtable = NIL;
2920 inner->jointree = jt;
2923#if PG_VERSION_NUM >= 160000
2924 inner->rteperminfos = NIL;
2927 orig_to_inner = palloc0((natoms + 1) *
sizeof(
int));
2930 for (j = 0; j < natoms; j++) {
2931 RangeTblEntry *src_rte, *cloned;
2934 if (atom_to_comp[j] != k)
2936 src_rte = (RangeTblEntry *) list_nth(q->rtable, j);
2937 cloned = (RangeTblEntry *) copyObject(src_rte);
2938#if PG_VERSION_NUM >= 160000
2939 if (cloned->perminfoindex != 0
2940 && q->rteperminfos != NIL
2941 && (
int) cloned->perminfoindex <= list_length(q->rteperminfos)) {
2942 RTEPermissionInfo *rpi = list_nth_node(RTEPermissionInfo,
2944 cloned->perminfoindex - 1);
2945 inner->rteperminfos =
2946 lappend(inner->rteperminfos, copyObject(rpi));
2947 cloned->perminfoindex = (Index) list_length(inner->rteperminfos);
2949 cloned->perminfoindex = 0;
2952 inner->rtable = lappend(inner->rtable, cloned);
2953 inner_rtindex = list_length(inner->rtable);
2954 orig_to_inner[j + 1] = inner_rtindex;
2955 rtr = makeNode(RangeTblRef);
2956 rtr->rtindex = inner_rtindex;
2957 jt->fromlist = lappend(jt->fromlist, rtr);
2967 foreach (qlc, inner_quals[k])
2968 all = lappend(all, copyObject((Node *) lfirst(qlc)));
2969 for (j = 0; j < natoms; j++) {
2970 if (atom_to_comp[j] != k)
2972 foreach (qlc, per_atom_quals[j])
2973 all = lappend(all, copyObject((Node *) lfirst(qlc)));
2977 List *remapped = NIL;
2980 foreach (qlc, all) {
2981 Node *qq = (Node *) lfirst(qlc);
2983 remapped = lappend(remapped, qq);
2985 if (list_length(remapped) == 1)
2986 jt->quals = (Node *) linitial(remapped);
2988 jt->quals = (Node *) makeBoolExpr(AND_EXPR, remapped, -1);
2996 inner->targetList = NIL;
2997 inner->groupClause = NIL;
3000 foreach (tlc, inner_tlists[k]) {
3001 TargetEntry *src_te = (TargetEntry *) lfirst(tlc);
3002 TargetEntry *new_te = (TargetEntry *) copyObject(src_te);
3004 SortGroupClause *sgc = makeNode(SortGroupClause);
3009 (Node *) new_te->expr, &rctx);
3012 new_te->resno = (AttrNumber) inner_attno;
3013 new_te->ressortgroupref = (Index) inner_sgr;
3014 new_te->resjunk =
false;
3025 while ((v = bms_next_member(vctx.
varnos, v)) >= 0) {
3026 if (v >= 1 && v <= natoms && atom_to_comp[v - 1] == k)
3027 atom_to_inner_attno[v - 1] = inner_attno;
3031 inner->targetList = lappend(inner->targetList, new_te);
3033 expr_type = exprType((Node *) new_te->expr);
3034 sgc->tleSortGroupRef = (Index) inner_sgr;
3035 get_sort_group_operators(expr_type,
true,
true,
false,
3036 &sgc->sortop, &sgc->eqop, NULL,
3038 sgc->nulls_first =
false;
3039 inner->groupClause = lappend(inner->groupClause, sgc);
3043 inner_queries[k] = inner;
3044 pfree(orig_to_inner);
3052 outer = copyObject(q);
3053 outer->rtable = NIL;
3054 outer->jointree->fromlist = NIL;
3055 outer->jointree->quals = (outer_resid == NIL) ? NULL
3056 : (list_length(outer_resid) == 1
3057 ? (Node *) linitial(outer_resid)
3058 : (Node *) makeBoolExpr(AND_EXPR,
3060#if PG_VERSION_NUM >= 160000
3061 outer->rteperminfos = NIL;
3063 for (k = 0; k < ncomp; k++) {
3064 RangeTblEntry *new_rte = makeNode(RangeTblEntry);
3065 Alias *eref = makeNode(Alias);
3069 eref->aliasname = psprintf(
"provsql_component_%d", k + 1);
3070 eref->colnames = NIL;
3071 foreach (tlc, inner_queries[k]->targetList) {
3072 TargetEntry *ite = (TargetEntry *) lfirst(tlc);
3074 eref->colnames = lappend(eref->colnames,
3075 makeString(ite->resname
3076 ? pstrdup(ite->resname)
3077 : psprintf(
"col_%d", slot_idx)));
3080 new_rte->rtekind = RTE_SUBQUERY;
3081 new_rte->subquery = inner_queries[k];
3082 new_rte->alias = NULL;
3083 new_rte->eref = eref;
3084 new_rte->inFromCl =
true;
3085 new_rte->lateral =
false;
3086#if PG_VERSION_NUM < 160000
3087 new_rte->requiredPerms = 0;
3090 outer->rtable = lappend(outer->rtable, new_rte);
3091 comp_outer_rtindex[k] = (Index) list_length(outer->rtable);
3093 RangeTblRef *rtr = makeNode(RangeTblRef);
3094 rtr->rtindex = comp_outer_rtindex[k];
3095 outer->jointree->fromlist = lappend(outer->jointree->fromlist, rtr);
3107 (Node *) outer->targetList, &tctx);
3108 if (outer->jointree->quals)
3109 outer->jointree->quals =
3113 provsql_notice(
"safe-query multi-component rewrite bailed: a Var "
3114 "has no exposed column in its component's inner "
3116 pfree(inner_queries);
3123 provsql_notice(
"safe-query multi-component rewrite fired: split %d "
3124 "atoms into %d disconnected component%s",
3125 natoms, ncomp, ncomp == 1 ?
"" :
"s");
3127 pfree(inner_queries);
3129 pfree(inner_tlists);
3130 pfree(comp_inner_idx);
3131 pfree(atom_to_inner_idx);
3132 pfree(atom_to_inner_attno);
3133 pfree(comp_outer_rtindex);
3180 Node **residual_in_out) {
3181 int natoms = list_length(q->rtable);
3183 List *eq_pairs = NIL;
3189 bool *is_constant_class;
3190 Const **class_const_value;
3191 List *all_const_conjuncts = NIL;
3199 expression_tree_walker((Node *) q->targetList,
3201 if (*residual_in_out)
3202 expression_tree_walker(*residual_in_out,
3204 if (per_atom_quals != NULL) {
3206 for (j = 0; j < natoms; j++) {
3208 foreach (qlc, per_atom_quals[j])
3209 expression_tree_walker((Node *) lfirst(qlc),
3213 nvars = list_length(vctx.
vars);
3217 vars_arr = palloc(nvars *
sizeof(Var *));
3218 cls = palloc(nvars *
sizeof(
int));
3220 foreach (lc, vctx.
vars) {
3221 vars_arr[i] = (Var *) lfirst(lc);
3227 if (*residual_in_out)
3229 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
3231 int li, ri, ci, cj, k;
3232 lv = (Var *) lfirst(lc);
3234 rv = (Var *) lfirst(lc);
3237 if (li < 0 || ri < 0)
3243 for (k = 0; k < nvars; k++)
3250 is_constant_class = palloc0(nvars *
sizeof(
bool));
3251 class_const_value = palloc0(nvars *
sizeof(Const *));
3252 if (per_atom_quals != NULL) {
3254 for (j = 0; j < natoms; j++) {
3256 foreach (qlc, per_atom_quals[j])
3257 all_const_conjuncts = lappend(all_const_conjuncts, lfirst(qlc));
3260 if (*residual_in_out)
3265 foreach (qlc, all_const_conjuncts) {
3266 Expr *e = (Expr *) lfirst(qlc);
3276 if (!is_constant_class[root]) {
3277 is_constant_class[root] =
true;
3278 class_const_value[root] = k;
3282 list_free(all_const_conjuncts);
3286 if (per_atom_quals != NULL) {
3287 for (i = 0; i < nvars; i++) {
3289 Var *vp = vars_arr[i];
3290 Const *k = class_const_value[root];
3292 bool already =
false;
3298 if (!is_constant_class[root] || k == NULL)
3300 if (vp->varno < 1 || (
int) vp->varno > natoms)
3302 atom_idx = (int) vp->varno - 1;
3303 foreach (qlc, per_atom_quals[atom_idx]) {
3305 &v_existing, &k_existing)
3306 && v_existing->varno == vp->varno
3307 && v_existing->varattno == vp->varattno) {
3315 if (eqop == InvalidOid)
3317 new_op = (OpExpr *) makeNode(OpExpr);
3318 new_op->opno = eqop;
3319 new_op->opfuncid = InvalidOid;
3320 new_op->opresulttype = BOOLOID;
3321 new_op->opretset =
false;
3322 new_op->opcollid = InvalidOid;
3323 new_op->inputcollid = vp->varcollid;
3324 new_op->args = list_make2(copyObject(vp), copyObject(k));
3325 new_op->location = -1;
3326 per_atom_quals[atom_idx] =
3327 lappend(per_atom_quals[atom_idx], new_op);
3345 if (*residual_in_out != NULL) {
3346 List *conjuncts = NIL;
3350 foreach (qlc, conjuncts) {
3351 Node *cj = (Node *) lfirst(qlc);
3354 bool all_constant =
true;
3355 bool any_var =
false;
3357 foreach (vlc, cv.
vars) {
3358 Var *v = (Var *) lfirst(vlc);
3361 if (idx < 0 || !is_constant_class[cls[idx]]) {
3362 all_constant =
false;
3367 if (any_var && all_constant)
3369 kept = lappend(kept, cj);
3372 *residual_in_out = NULL;
3373 else if (list_length(kept) == 1)
3374 *residual_in_out = (Node *) linitial(kept);
3376 *residual_in_out = (Node *) makeBoolExpr(AND_EXPR, kept, -1);
3377 list_free(conjuncts);
3380 pfree(is_constant_class);
3381 pfree(class_const_value);
3486 int natoms = list_length(q->rtable);
3491 List *eq_pairs = NIL;
3512 foreach (lc, q->rtable) {
3513 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3515 if (rte->rtekind != RTE_RELATION)
3517 foreach (lc2, seen_relids) {
3518 if (lfirst_oid(lc2) == rte->relid) {
3525 seen_relids = lappend_oid(seen_relids, rte->relid);
3527 list_free(seen_relids);
3537 expression_tree_walker((Node *) q->targetList,
3539 if (q->jointree && q->jointree->quals)
3540 expression_tree_walker(q->jointree->quals,
3542 nvars = list_length(vctx.
vars);
3546 vars_arr = palloc(nvars *
sizeof(Var *));
3547 cls = palloc(nvars *
sizeof(
int));
3549 foreach (lc, vctx.
vars) {
3550 vars_arr[i] = (Var *) lfirst(lc);
3554 if (q->jointree && q->jointree->quals)
3556 for (lc = list_head(eq_pairs); lc != NULL; lc =
my_lnext(eq_pairs, lc)) {
3558 int li, ri, ci, cj, k;
3559 lv = (Var *) lfirst(lc);
3561 rv = (Var *) lfirst(lc);
3564 if (li < 0 || ri < 0)
3570 for (k = 0; k < nvars; k++)
3579 keeper = palloc(natoms *
sizeof(
int));
3580 for (j = 0; j < natoms; j++)
3583 any_unified =
false;
3584 for (j = 0; j < natoms; j++) {
3585 RangeTblEntry *rte_j;
3588 bool all_pairs_unify;
3590 ListCell *lc_a, *lc_b;
3593 rte_j = (RangeTblEntry *) list_nth(q->rtable, j);
3594 if (rte_j->rtekind != RTE_RELATION)
3599 group = list_make1_int(j);
3600 for (k = j + 1; k < natoms; k++) {
3601 RangeTblEntry *rte_k = (RangeTblEntry *) list_nth(q->rtable, k);
3602 if (rte_k->rtekind != RTE_RELATION)
3604 if (rte_k->relid != rte_j->relid)
3606 group = lappend_int(group, k);
3608 if (list_length(group) < 2) {
3619 all_pairs_unify =
true;
3620 foreach (lc_a, group) {
3621 int aa = lfirst_int(lc_a);
3622 foreach (lc_b, group) {
3623 int bb = lfirst_int(lc_b);
3624 bool this_pair_unifies =
false;
3628 for (ki = 0; ki < keys.
key_n; ki++) {
3630 bool all_pk_equated =
true;
3632 for (kc = 0; kc < key->
col_n; kc++) {
3633 AttrNumber attno = key->
cols[kc];
3638 if (idx_a < 0 || idx_b < 0 || cls[idx_a] != cls[idx_b]) {
3639 all_pk_equated =
false;
3643 if (all_pk_equated) {
3644 this_pair_unifies =
true;
3648 if (!this_pair_unifies) {
3649 all_pairs_unify =
false;
3653 if (!all_pairs_unify)
3657 if (all_pairs_unify) {
3658 foreach (lc_a, group) {
3659 int aa = lfirst_int(lc_a);
3680 old_to_new = palloc0((natoms + 1) *
sizeof(
int));
3682 for (j = 0; j < natoms; j++) {
3684 while (keeper[root] != root)
3685 root = keeper[root];
3687 old_to_new[j + 1] = new_idx++;
3689 for (j = 0; j < natoms; j++) {
3691 while (keeper[root] != root)
3692 root = keeper[root];
3694 old_to_new[j + 1] = old_to_new[root + 1];
3699 for (j = 0; j < natoms; j++) {
3701 while (keeper[root] != root)
3702 root = keeper[root];
3704 RangeTblEntry *rte = (RangeTblEntry *) list_nth(q->rtable, j);
3705 new_rtable = lappend(new_rtable, copyObject(rte));
3716 seen_new = palloc0((new_idx + 1) *
sizeof(
bool));
3718 foreach (lc, q->jointree->fromlist) {
3719 Node *n = (Node *) lfirst(lc);
3720 if (IsA(n, RangeTblRef)) {
3721 RangeTblRef *rtr = (RangeTblRef *) n;
3722 int new_no = old_to_new[rtr->rtindex];
3726 if (seen_new[new_no])
3728 seen_new[new_no] =
true;
3729 clone = (RangeTblRef *) copyObject(rtr);
3730 clone->rtindex = new_no;
3731 new_fromlist = lappend(new_fromlist, clone);
3733 new_fromlist = lappend(new_fromlist, copyObject(n));
3743 new_q = (Query *) copyObject(q);
3744 new_q->rtable = new_rtable;
3745 if (new_q->jointree)
3746 new_q->jointree->fromlist = new_fromlist;
3747#if PG_VERSION_NUM >= 160000
3755 new_q->targetList = (List *)
3757 if (new_q->jointree && new_q->jointree->quals)
3758 new_q->jointree->quals =