Skip to content

Commit 8af4fe0

Browse files
committed
Add forgotten files
1 parent d62fa70 commit 8af4fe0

File tree

4 files changed

+260
-22
lines changed

4 files changed

+260
-22
lines changed

contrib/pg_exchange/partutils.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* partutils.c
3+
*
4+
*/
5+
#include "partutils.h"
6+
7+
#include "optimizer/paths.h"
8+
#include "partitioning/partbounds.h"
9+
10+
11+
bool
12+
build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel,
13+
RelOptInfo *inner_rel, List *restrictlist,
14+
JoinType jointype)
15+
{
16+
int partnatts;
17+
int cnt;
18+
PartitionScheme part_scheme;
19+
20+
/*
21+
* We can only consider this join as an input to further partitionwise
22+
* joins if (a) the input relations are partitioned and have
23+
* consider_partitionwise_join=true, (b) the partition schemes match, and
24+
* (c) we can identify an equi-join between the partition keys. Note that
25+
* if it were possible for have_partkey_equi_join to return different
26+
* answers for the same joinrel depending on which join ordering we try
27+
* first, this logic would break. That shouldn't happen, though, because
28+
* of the way the query planner deduces implied equalities and reorders
29+
* the joins. Please see optimizer/README for details.
30+
*/
31+
if (!IS_PARTITIONED_REL(outer_rel) || !IS_PARTITIONED_REL(inner_rel) ||
32+
outer_rel->part_scheme != inner_rel->part_scheme ||
33+
!have_partkey_equi_join(joinrel, outer_rel, inner_rel,
34+
jointype, restrictlist))
35+
return false;
36+
37+
part_scheme = outer_rel->part_scheme;
38+
39+
Assert(REL_HAS_ALL_PART_PROPS(outer_rel) &&
40+
REL_HAS_ALL_PART_PROPS(inner_rel));
41+
42+
/*
43+
* For now, our partition matching algorithm can match partitions only
44+
* when the partition bounds of the joining relations are exactly same.
45+
* So, bail out otherwise.
46+
*/
47+
if (outer_rel->nparts != inner_rel->nparts ||
48+
!partition_bounds_equal(part_scheme->partnatts,
49+
part_scheme->parttyplen,
50+
part_scheme->parttypbyval,
51+
outer_rel->boundinfo, inner_rel->boundinfo))
52+
{
53+
Assert(0);
54+
Assert(!IS_PARTITIONED_REL(joinrel));
55+
return false;
56+
}
57+
58+
/*
59+
* This function will be called only once for each joinrel, hence it
60+
* should not have partition scheme, partition bounds, partition key
61+
* expressions and array for storing child relations set.
62+
*/
63+
Assert(!joinrel->part_scheme && !joinrel->partexprs &&
64+
!joinrel->nullable_partexprs && !joinrel->part_rels &&
65+
!joinrel->boundinfo);
66+
67+
/*
68+
* Join relation is partitioned using the same partitioning scheme as the
69+
* joining relations and has same bounds.
70+
*/
71+
joinrel->part_scheme = part_scheme;
72+
joinrel->boundinfo = outer_rel->boundinfo;
73+
partnatts = joinrel->part_scheme->partnatts;
74+
joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
75+
joinrel->nullable_partexprs =
76+
(List **) palloc0(sizeof(List *) * partnatts);
77+
joinrel->nparts = outer_rel->nparts;
78+
joinrel->part_rels =
79+
(RelOptInfo **) palloc0(sizeof(RelOptInfo *) * joinrel->nparts);
80+
81+
/*
82+
* Construct partition keys for the join.
83+
*
84+
* An INNER join between two partitioned relations can be regarded as
85+
* partitioned by either key expression. For example, A INNER JOIN B ON
86+
* A.a = B.b can be regarded as partitioned on A.a or on B.b; they are
87+
* equivalent.
88+
*
89+
* For a SEMI or ANTI join, the result can only be regarded as being
90+
* partitioned in the same manner as the outer side, since the inner
91+
* columns are not retained.
92+
*
93+
* An OUTER join like (A LEFT JOIN B ON A.a = B.b) may produce rows with
94+
* B.b NULL. These rows may not fit the partitioning conditions imposed on
95+
* B.b. Hence, strictly speaking, the join is not partitioned by B.b and
96+
* thus partition keys of an OUTER join should include partition key
97+
* expressions from the OUTER side only. However, because all
98+
* commonly-used comparison operators are strict, the presence of nulls on
99+
* the outer side doesn't cause any problem; they can't match anything at
100+
* future join levels anyway. Therefore, we track two sets of
101+
* expressions: those that authentically partition the relation
102+
* (partexprs) and those that partition the relation with the exception
103+
* that extra nulls may be present (nullable_partexprs). When the
104+
* comparison operator is strict, the latter is just as good as the
105+
* former.
106+
*/
107+
for (cnt = 0; cnt < partnatts; cnt++)
108+
{
109+
List *outer_expr;
110+
List *outer_null_expr;
111+
List *inner_expr;
112+
List *inner_null_expr;
113+
List *partexpr = NIL;
114+
List *nullable_partexpr = NIL;
115+
116+
outer_expr = list_copy(outer_rel->partexprs[cnt]);
117+
outer_null_expr = list_copy(outer_rel->nullable_partexprs[cnt]);
118+
inner_expr = list_copy(inner_rel->partexprs[cnt]);
119+
inner_null_expr = list_copy(inner_rel->nullable_partexprs[cnt]);
120+
121+
switch (jointype)
122+
{
123+
case JOIN_INNER:
124+
partexpr = list_concat(outer_expr, inner_expr);
125+
nullable_partexpr = list_concat(outer_null_expr,
126+
inner_null_expr);
127+
break;
128+
129+
case JOIN_SEMI:
130+
case JOIN_ANTI:
131+
partexpr = outer_expr;
132+
nullable_partexpr = outer_null_expr;
133+
break;
134+
135+
case JOIN_LEFT:
136+
partexpr = outer_expr;
137+
nullable_partexpr = list_concat(inner_expr,
138+
outer_null_expr);
139+
nullable_partexpr = list_concat(nullable_partexpr,
140+
inner_null_expr);
141+
break;
142+
143+
case JOIN_FULL:
144+
nullable_partexpr = list_concat(outer_expr,
145+
inner_expr);
146+
nullable_partexpr = list_concat(nullable_partexpr,
147+
outer_null_expr);
148+
nullable_partexpr = list_concat(nullable_partexpr,
149+
inner_null_expr);
150+
break;
151+
152+
default:
153+
elog(ERROR, "unrecognized join type: %d", (int) jointype);
154+
155+
}
156+
157+
joinrel->partexprs[cnt] = partexpr;
158+
joinrel->nullable_partexprs[cnt] = nullable_partexpr;
159+
}
160+
return true;
161+
}

contrib/pg_exchange/partutils.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* partutils.h
3+
*
4+
*/
5+
6+
#ifndef PARTUTILS_H_
7+
#define PARTUTILS_H_
8+
9+
#include "postgres.h"
10+
11+
#include "nodes/relation.h"
12+
13+
extern bool build_joinrel_partition_info(RelOptInfo *joinrel,
14+
RelOptInfo *outer_rel,
15+
RelOptInfo *inner_rel,
16+
List *restrictlist,
17+
JoinType jointype);
18+
19+
#endif /* PARTUTILS_H_ */
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
CREATE SERVER remote1 FOREIGN DATA WRAPPER postgres_fdw OPTIONS (port '5432', use_remote_estimate 'on');
2+
CREATE USER MAPPING FOR PUBLIC SERVER remote1;
3+
CREATE SERVER remote2 FOREIGN DATA WRAPPER postgres_fdw OPTIONS (port '5433', use_remote_estimate 'on');
4+
CREATE USER MAPPING FOR PUBLIC SERVER remote2;
5+
6+
DROP TABLE IF EXISTS pt cascade;
7+
CREATE TABLE pt (
8+
id integer not null,
9+
payload integer,
10+
test integer
11+
) PARTITION BY hash (id);
12+
13+
CREATE FOREIGN TABLE pt_0 PARTITION OF pt FOR VALUES WITH (modulus 3, remainder 0) SERVER remote1;
14+
CREATE FOREIGN TABLE pt_1 PARTITION OF pt FOR VALUES WITH (modulus 3, remainder 1) SERVER remote2;
15+
CREATE TABLE pt_2 PARTITION OF pt FOR VALUES WITH (modulus 3, remainder 2);
16+
17+
DROP TABLE IF EXISTS rt cascade;
18+
CREATE TABLE rt (
19+
id integer not null,
20+
payload integer,
21+
test integer
22+
) PARTITION BY hash (id);
23+
24+
CREATE FOREIGN TABLE rt_0 PARTITION OF rt FOR VALUES WITH (modulus 3, remainder 0) SERVER remote1;
25+
CREATE FOREIGN TABLE rt_1 PARTITION OF rt FOR VALUES WITH (modulus 3, remainder 1) SERVER remote2;
26+
CREATE TABLE rt_2 PARTITION OF rt FOR VALUES WITH (modulus 3, remainder 2);

contrib/pg_execplan/tests/init_shardman.sh

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,48 +20,80 @@ export PGDATABASE=test_base
2020
pkill -9 postgres || true
2121
sleep 1
2222
rm -rf $PGINSTALL || true
23-
rm -rf PGDATA_Master || true
24-
rm -rf PGDATA_Slave || true
25-
rm -rf master.log || true
26-
rm -rf slave.log || true
27-
mkdir PGDATA_Master
28-
mkdir PGDATA_Slave
23+
rm -rf PGDATA_n0 || true
24+
rm -rf PGDATA_n1 || true
25+
rm -rf PGDATA_n2 || true
26+
rm -rf n0.log || true
27+
rm -rf n1.log || true
28+
rm -rf n2.log || true
29+
mkdir PGDATA_n0
30+
mkdir PGDATA_n1
31+
mkdir PGDATA_n2
2932

3033
# Building project
3134
make > /dev/null
3235
make -C contrib > /dev/null
3336
make install > /dev/null
3437
make -C contrib install > /dev/null
3538

36-
initdb -D PGDATA_Master -E UTF8 --locale=C
37-
initdb -D PGDATA_Slave -E UTF8 --locale=C
38-
echo "shared_preload_libraries = 'postgres_fdw, pg_execplan, pg_exchange'" >> PGDATA_Master/postgresql.conf
39-
echo "pg_exchange.node_number1=0" >> PGDATA_Master/postgresql.conf
40-
#echo "log_min_messages = debug1" >> PGDATA_Master/postgresql.conf
41-
echo "shared_preload_libraries = 'postgres_fdw, pg_execplan, pg_exchange'" >> PGDATA_Slave/postgresql.conf
42-
echo "pg_exchange.node_number1=1" >> PGDATA_Slave/postgresql.conf
39+
initdb -D PGDATA_n0 -E UTF8 --locale=C
40+
initdb -D PGDATA_n1 -E UTF8 --locale=C
41+
initdb -D PGDATA_n2 -E UTF8 --locale=C
42+
43+
echo "shared_preload_libraries = 'postgres_fdw, pg_exchange'" >> PGDATA_n0/postgresql.conf
44+
echo "shared_preload_libraries = 'postgres_fdw, pg_exchange'" >> PGDATA_n1/postgresql.conf
45+
echo "shared_preload_libraries = 'postgres_fdw, pg_exchange'" >> PGDATA_n2/postgresql.conf
46+
4347
#echo "log_min_messages = debug1" >> PGDATA_Slave/postgresql.conf
4448

45-
pg_ctl -w -c -o "-p 5433" -D PGDATA_Slave -l slave.log start
46-
pg_ctl -w -c -o "-p 5432" -D PGDATA_Master -l master.log start
49+
pg_ctl -w -c -o "-p 5434" -D PGDATA_n2 -l n2.log start
50+
pg_ctl -w -c -o "-p 5433" -D PGDATA_n1 -l n1.log start
51+
pg_ctl -w -c -o "-p 5432" -D PGDATA_n0 -l n0.log start
4752
createdb -p 5432
4853
createdb -p 5433
54+
createdb -p 5434
4955

56+
psql -p 5434 -f "contrib/pg_execplan/tests/init_node_overall.sql" &
5057
psql -p 5433 -f "contrib/pg_execplan/tests/init_node_overall.sql" &
5158
psql -p 5432 -f "contrib/pg_execplan/tests/init_node_overall.sql"
5259

53-
psql -p 5432 -c "CREATE SERVER $remoteSrvName FOREIGN DATA WRAPPER postgres_fdw
54-
OPTIONS (port '5433', use_remote_estimate 'on');
55-
CREATE USER MAPPING FOR PUBLIC SERVER $remoteSrvName;"
56-
psql -p 5433 -c "CREATE SERVER $remoteSrvName FOREIGN DATA WRAPPER postgres_fdw
57-
OPTIONS (port '5432', use_remote_estimate 'on');
58-
CREATE USER MAPPING FOR PUBLIC SERVER $remoteSrvName;"
60+
#psql -p 5432 -c "CREATE SERVER remote1 FOREIGN DATA WRAPPER postgres_fdw
61+
# OPTIONS (port '5433', use_remote_estimate 'on');
62+
# CREATE USER MAPPING FOR PUBLIC SERVER remote1;"
63+
#psql -p 5432 -c "CREATE SERVER remote2 FOREIGN DATA WRAPPER postgres_fdw
64+
# OPTIONS (port '5434', use_remote_estimate 'on');
65+
# CREATE USER MAPPING FOR PUBLIC SERVER remote2;"
66+
67+
#psql -p 5433 -c "CREATE SERVER remote1 FOREIGN DATA WRAPPER postgres_fdw
68+
# OPTIONS (port '5432', use_remote_estimate 'on');
69+
# CREATE USER MAPPING FOR PUBLIC SERVER remote1;"
70+
#psql -p 5433 -c "CREATE SERVER remote2 FOREIGN DATA WRAPPER postgres_fdw
71+
# OPTIONS (port '5434', use_remote_estimate 'on');
72+
# CREATE USER MAPPING FOR PUBLIC SERVER remote2;"
73+
74+
#psql -p 5434 -c "CREATE SERVER remote1 FOREIGN DATA WRAPPER postgres_fdw
75+
# OPTIONS (port '5432', use_remote_estimate 'on');
76+
# CREATE USER MAPPING FOR PUBLIC SERVER remote1;"
77+
#psql -p 5434 -c "CREATE SERVER remote2 FOREIGN DATA WRAPPER postgres_fdw
78+
# OPTIONS (port '5433', use_remote_estimate 'on');
79+
# CREATE USER MAPPING FOR PUBLIC SERVER remote2;"
5980

6081
# Change OID counter at slave node.
6182
psql -p 5433 -c "CREATE TABLE t2 (id Serial, b INT, PRIMARY KEY(id));"
6283
psql -p 5433 -c "DROP TABLE t2;"
6384

6485
psql -p 5432 -f "contrib/pg_execplan/tests/init_node0.sql"
6586
psql -p 5433 -f "contrib/pg_execplan/tests/init_node1.sql"
87+
psql -p 5434 -f "contrib/pg_execplan/tests/init_node2.sql"
88+
89+
psql -p 5432 -c "INSERT INTO pt (id, payload, test) (SELECT a.*, b.*,0 FROM
90+
generate_series(1, 10) as a, generate_series(1, 3) as b);"
91+
psql -p 5432 -c "INSERT INTO rt (id, payload, test) (SELECT a.*, 0,0 FROM
92+
generate_series(1, 10) as a);"
93+
94+
psql -p 5432 -c "INSERT INTO a (a1, a2) (SELECT *, 1 FROM generate_series(1, 50));"
95+
psql -p 5432 -c "INSERT INTO b (b1, b2) (SELECT *, 0 FROM generate_series(1, 10));"
6696

67-
psql -p 5432 -c "INSERT INTO pt (id, payload, test) (SELECT *, 0,0 FROM generate_series(1, 1000));"
97+
psql -p 5432 -c "VACUUM FULL;"
98+
psql -p 5433 -c "VACUUM FULL;"
99+
psql -p 5434 -c "VACUUM FULL;"

0 commit comments

Comments
 (0)