From f898d83422d3324ff2740aa52660825c321a2220 Mon Sep 17 00:00:00 2001 From: reshke Date: Wed, 5 Feb 2025 12:09:55 +0000 Subject: [PATCH 1/2] Support routing based purely on target list. Also bump lyx with NOT IN support. --- go.mod | 2 +- go.sum | 2 + router/qrouter/proxy_routing.go | 10 ++ test/regress/schedule/router | 1 + test/regress/tests/router/expected/ddl.out | 2 + .../router/expected/target_list_routing.out | 98 +++++++++++++++++++ test/regress/tests/router/sql/ddl.sql | 2 + .../tests/router/sql/target_list_routing.sql | 32 ++++++ 8 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 test/regress/tests/router/expected/target_list_routing.out create mode 100644 test/regress/tests/router/sql/target_list_routing.sql diff --git a/go.mod b/go.mod index 961033863..8fd8afca8 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/lib/pq v1.10.9 github.com/libp2p/go-reuseport v0.4.0 github.com/opentracing/opentracing-go v1.2.0 - github.com/pg-sharding/lyx v0.0.0-20250205095044-3d4593d06b55 + github.com/pg-sharding/lyx v0.0.0-20250205112935-771f430d614f github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/sevlyar/go-daemon v0.1.6 diff --git a/go.sum b/go.sum index 5270d06c5..c415d814a 100644 --- a/go.sum +++ b/go.sum @@ -170,6 +170,8 @@ github.com/pg-sharding/lyx v0.0.0-20250203080453-fc228647d0af h1:NnvzvVzlzj/FHdD github.com/pg-sharding/lyx v0.0.0-20250203080453-fc228647d0af/go.mod h1:2dPBQAhqv/30mhzj2yBXQkXhsGJQ8GhM+oWOfbGua58= github.com/pg-sharding/lyx v0.0.0-20250205095044-3d4593d06b55 h1:Z6yI8iwmpuinCD8NOTSBHzuZRAxhD6kGfFU+e0MzhHo= github.com/pg-sharding/lyx v0.0.0-20250205095044-3d4593d06b55/go.mod h1:2dPBQAhqv/30mhzj2yBXQkXhsGJQ8GhM+oWOfbGua58= +github.com/pg-sharding/lyx v0.0.0-20250205112935-771f430d614f h1:z4UC1xwZhRjpx6S2P+crm6nT1b33ptVxK5T0eHHSQWY= +github.com/pg-sharding/lyx v0.0.0-20250205112935-771f430d614f/go.mod h1:2dPBQAhqv/30mhzj2yBXQkXhsGJQ8GhM+oWOfbGua58= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/router/qrouter/proxy_routing.go b/router/qrouter/proxy_routing.go index 777f7d794..7b2735670 100644 --- a/router/qrouter/proxy_routing.go +++ b/router/qrouter/proxy_routing.go @@ -708,6 +708,7 @@ func (qr *ProxyQrouter) routeWithRules(ctx context.Context, rm *rmeta.RoutingMet /* We cannot route SQL statements without a FROM clause. However, there are a few cases to consider. */ if len(node.FromClause) == 0 && (node.LArg == nil || node.RArg == nil) { + for _, expr := range node.TargetList { switch e := expr.(type) { /* Special cases for SELECT current_schema(), SELECT set_config(...), and SELECT pg_is_in_recovery() */ @@ -717,6 +718,12 @@ func (qr *ProxyQrouter) routeWithRules(ctx context.Context, rm *rmeta.RoutingMet if e.Name == "current_schema" || e.Name == "set_config" || e.Name == "pg_is_in_recovery" || e.Name == "version" { return plan.RandomDispatchPlan{}, ro, nil } + for _, innerExp := range e.Args { + switch iE := innerExp.(type) { + case *lyx.Select: + _, _ = qr.planQueryV1(ctx, iE, rm) + } + } /* Expression like SELECT 1, SELECT 'a', SELECT 1.0, SELECT true, SELECT false */ case *lyx.AExprIConst, *lyx.AExprSConst, *lyx.AExprNConst, *lyx.AExprBConst: return plan.RandomDispatchPlan{}, ro, nil @@ -726,8 +733,11 @@ func (qr *ProxyQrouter) routeWithRules(ctx context.Context, rm *rmeta.RoutingMet if e.ColName == "current_schema" { return plan.RandomDispatchPlan{}, ro, nil } + case *lyx.Select: + _, _ = qr.planQueryV1(ctx, e, rm) } } + } else if node.LArg != nil && node.RArg != nil { /* deparse populates the FromClause info, * so it do recurse into both branches, even if an error is encountered diff --git a/test/regress/schedule/router b/test/regress/schedule/router index 99e374a49..484b25507 100644 --- a/test/regress/schedule/router +++ b/test/regress/schedule/router @@ -20,6 +20,7 @@ test: copy_reference_table test: copy_inside_singleshard_connection test: distributed_relation_multishard_modify test: part_table +test: target_list_routing test: reference_table test: ddl test: engine_v2 diff --git a/test/regress/tests/router/expected/ddl.out b/test/regress/tests/router/expected/ddl.out index 09c1ea8da..bf148a08a 100644 --- a/test/regress/tests/router/expected/ddl.out +++ b/test/regress/tests/router/expected/ddl.out @@ -51,6 +51,8 @@ NOTICE: send query to shard(s) : sh1,sh2,sh3,sh4 ALTER TABLE "table_2" RENAME TO "table_1"; ALTER TABLE "tmp" RENAME TO "table_2"; COMMIT; +DROP SCHEMA sh1; +NOTICE: send query to shard(s) : sh1,sh2,sh3,sh4 DROP TABLE table_1 CASCADE; NOTICE: send query to shard(s) : sh1,sh2,sh3,sh4 DROP TABLE table_2; diff --git a/test/regress/tests/router/expected/target_list_routing.out b/test/regress/tests/router/expected/target_list_routing.out new file mode 100644 index 000000000..f08ed9df1 --- /dev/null +++ b/test/regress/tests/router/expected/target_list_routing.out @@ -0,0 +1,98 @@ +\c spqr-console + + SPQR router admin console + Here you can configure your routing rules +------------------------------------------------ + You can find documentation here +https://github.com/pg-sharding/spqr/tree/master/docs + +CREATE DISTRIBUTION ds1 COLUMN TYPES integer; + add distribution +------------------------ + distribution id -> ds1 +(1 row) + +CREATE KEY RANGE kridi1 from 0 route to sh1 FOR DISTRIBUTION ds1; + add key range +--------------- + bound -> 0 +(1 row) + +CREATE KEY RANGE kridi2 from 11 route to sh2 FOR DISTRIBUTION ds1; + add key range +--------------- + bound -> 11 +(1 row) + +ALTER DISTRIBUTION ds1 ATTACH RELATION tlt1 DISTRIBUTION KEY i; + attach table +------------------------- + relation name -> tlt1 + distribution id -> ds1 +(2 rows) + +\c regress +CREATE SCHEMA sh2; +NOTICE: send query to shard(s) : sh1,sh2,sh3,sh4 +CREATE TABLE sh2.tlt1(i int, j int); +NOTICE: send query to shard(s) : sh1,sh2,sh3,sh4 +INSERT INTO sh2.tlt1 (i, j) VALUES(1, 12); +NOTICE: send query to shard(s) : sh1 +INSERT INTO sh2.tlt1 (i, j) VALUES(1, 12); +NOTICE: send query to shard(s) : sh1 +INSERT INTO sh2.tlt1 (i, j) VALUES(2, 13); +NOTICE: send query to shard(s) : sh1 +INSERT INTO sh2.tlt1 (i, j) VALUES(2, 13); +NOTICE: send query to shard(s) : sh1 +INSERT INTO sh2.tlt1 (i, j) VALUES(12, 12); +NOTICE: send query to shard(s) : sh2 +INSERT INTO sh2.tlt1 (i, j) VALUES(12, 14); +NOTICE: send query to shard(s) : sh2 +INSERT INTO sh2.tlt1 (i, j) VALUES(122, 124); +NOTICE: send query to shard(s) : sh2 +INSERT INTO sh2.tlt1 (i, j) VALUES(112, 124); +NOTICE: send query to shard(s) : sh2 +INSERT INTO sh2.tlt1 (i, j) VALUES(113, 125); +NOTICE: send query to shard(s) : sh2 +select (select sum(j) from sh2.tlt1 where i = 112); +NOTICE: send query to shard(s) : sh2 + sum +----- + 124 +(1 row) + +select (select sum(j) from sh2.tlt1 where i = 112), (select sum(j) from sh2.tlt1 where sh2.tlt1.i = 113); +NOTICE: send query to shard(s) : sh2 + sum | sum +-----+----- + 124 | 125 +(1 row) + +select coalesce((select sum(j) from sh2.tlt1 where i = 1), 0), coalesce((select sum(j) from sh2.tlt1 where i = 2 and j not in (select 12)), 0); +NOTICE: send query to shard(s) : sh1 + coalesce | coalesce +----------+---------- + 24 | 26 +(1 row) + +DROP SCHEMA sh2 CASCADE; +NOTICE: send query to shard(s) : sh1,sh2,sh3,sh4 +\c spqr-console + + SPQR router admin console + Here you can configure your routing rules +------------------------------------------------ + You can find documentation here +https://github.com/pg-sharding/spqr/tree/master/docs + +DROP DISTRIBUTION ALL CASCADE; + drop distribution +------------------------ + distribution id -> ds1 +(1 row) + +DROP KEY RANGE ALL; + drop key range +---------------- +(0 rows) + diff --git a/test/regress/tests/router/sql/ddl.sql b/test/regress/tests/router/sql/ddl.sql index 572e2a494..6b5d224b0 100644 --- a/test/regress/tests/router/sql/ddl.sql +++ b/test/regress/tests/router/sql/ddl.sql @@ -21,6 +21,8 @@ ALTER TABLE "table_2" RENAME TO "table_1"; ALTER TABLE "tmp" RENAME TO "table_2"; COMMIT; +DROP SCHEMA sh1; + DROP TABLE table_1 CASCADE; DROP TABLE table_2; diff --git a/test/regress/tests/router/sql/target_list_routing.sql b/test/regress/tests/router/sql/target_list_routing.sql new file mode 100644 index 000000000..85fc01a6e --- /dev/null +++ b/test/regress/tests/router/sql/target_list_routing.sql @@ -0,0 +1,32 @@ + +\c spqr-console +CREATE DISTRIBUTION ds1 COLUMN TYPES integer; +CREATE KEY RANGE kridi1 from 0 route to sh1 FOR DISTRIBUTION ds1; +CREATE KEY RANGE kridi2 from 11 route to sh2 FOR DISTRIBUTION ds1; +ALTER DISTRIBUTION ds1 ATTACH RELATION tlt1 DISTRIBUTION KEY i; + +\c regress + +CREATE SCHEMA sh2; +CREATE TABLE sh2.tlt1(i int, j int); + +INSERT INTO sh2.tlt1 (i, j) VALUES(1, 12); +INSERT INTO sh2.tlt1 (i, j) VALUES(1, 12); +INSERT INTO sh2.tlt1 (i, j) VALUES(2, 13); +INSERT INTO sh2.tlt1 (i, j) VALUES(2, 13); +INSERT INTO sh2.tlt1 (i, j) VALUES(12, 12); +INSERT INTO sh2.tlt1 (i, j) VALUES(12, 14); +INSERT INTO sh2.tlt1 (i, j) VALUES(122, 124); +INSERT INTO sh2.tlt1 (i, j) VALUES(112, 124); +INSERT INTO sh2.tlt1 (i, j) VALUES(113, 125); + +select (select sum(j) from sh2.tlt1 where i = 112); +select (select sum(j) from sh2.tlt1 where i = 112), (select sum(j) from sh2.tlt1 where sh2.tlt1.i = 113); +select coalesce((select sum(j) from sh2.tlt1 where i = 1), 0), coalesce((select sum(j) from sh2.tlt1 where i = 2 and j not in (select 12)), 0); + +DROP SCHEMA sh2 CASCADE; + +\c spqr-console +DROP DISTRIBUTION ALL CASCADE; +DROP KEY RANGE ALL; + From 63b89d95e0bba42de421dd5d1bcc817de60a52db Mon Sep 17 00:00:00 2001 From: Yury Frolov <57130330+EinKrebs@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:52:15 +0500 Subject: [PATCH 2/2] Update router/qrouter/proxy_routing.go --- router/qrouter/proxy_routing.go | 1 - 1 file changed, 1 deletion(-) diff --git a/router/qrouter/proxy_routing.go b/router/qrouter/proxy_routing.go index 7b2735670..d9e37731f 100644 --- a/router/qrouter/proxy_routing.go +++ b/router/qrouter/proxy_routing.go @@ -708,7 +708,6 @@ func (qr *ProxyQrouter) routeWithRules(ctx context.Context, rm *rmeta.RoutingMet /* We cannot route SQL statements without a FROM clause. However, there are a few cases to consider. */ if len(node.FromClause) == 0 && (node.LArg == nil || node.RArg == nil) { - for _, expr := range node.TargetList { switch e := expr.(type) { /* Special cases for SELECT current_schema(), SELECT set_config(...), and SELECT pg_is_in_recovery() */