From b3e94ecfff8e07f277559adc53b982047f1517e4 Mon Sep 17 00:00:00 2001 From: Arseniy Volynets <a.volynets@picodata.io> Date: Mon, 23 Sep 2024 11:00:47 +0300 Subject: [PATCH] feat(sql): support selects without scans --- CHANGELOG.md | 2 +- sbroad | 2 +- src/pgproto/backend/describe.rs | 1 + src/sql/router.rs | 16 +++---- test/int/test_sql.py | 80 +++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aba9ba85ed..9e8ecada3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ with the `YY.MINOR.MICRO` scheme. - SQL supports `lower` and `upper` string functions - Execute option `sql_vdbe_max_steps` was renamed to `vdbe_max_steps` - +- SQL supports `SELECT` statements without scans: `select 1` ## [24.5.1] - 2024-09-04 diff --git a/sbroad b/sbroad index 277d570ea0..97d2b81478 160000 --- a/sbroad +++ b/sbroad @@ -1 +1 @@ -Subproject commit 277d570ea01e33aacc06d72e8fb3d31d4d4e4c4e +Subproject commit 97d2b81478414c154cfa10c30c303f5ce0c8e0b7 diff --git a/src/pgproto/backend/describe.rs b/src/pgproto/backend/describe.rs index 7f077ed4ac..4d8465f68d 100644 --- a/src/pgproto/backend/describe.rs +++ b/src/pgproto/backend/describe.rs @@ -227,6 +227,7 @@ impl TryFrom<&Node<'_>> for CommandTag { | Relational::UnionAll { .. } | Relational::Values { .. } | Relational::ValuesRow { .. } + | Relational::SelectWithoutScan { .. } | Relational::Limit { .. } => Ok(CommandTag::Select), }, Node::Invalid(_) | Node::Expression(_) | Node::Parameter(_) => { diff --git a/src/sql/router.rs b/src/sql/router.rs index 328cb4b749..edd51f6d72 100644 --- a/src/sql/router.rs +++ b/src/sql/router.rs @@ -266,14 +266,6 @@ impl Router for RouterRuntime { type MetadataProvider = RouterMetadata; type VshardImplementor = Tier; - fn materialize_values( - &self, - exec_plan: &mut ExecutionPlan, - values_id: NodeId, - ) -> Result<VirtualTable, SbroadError> { - materialize_values(self, exec_plan, values_id) - } - fn metadata(&self) -> &impl MutexLike<Self::MetadataProvider> { &self.metadata } @@ -329,6 +321,14 @@ impl Router for RouterRuntime { let tier_name = tier_name.unwrap_or(¤t_instance_tier_name); get_tier_info(tier_name) } + + fn materialize_values( + &self, + exec_plan: &mut ExecutionPlan, + values_id: NodeId, + ) -> Result<VirtualTable, SbroadError> { + materialize_values(self, exec_plan, values_id) + } } pub(crate) fn calculate_bucket_id(tuple: &[&Value], bucket_count: u64) -> Result<u64, SbroadError> { diff --git a/test/int/test_sql.py b/test/int/test_sql.py index dc6217d5ff..0a6488006b 100644 --- a/test/int/test_sql.py +++ b/test/int/test_sql.py @@ -5319,3 +5319,83 @@ def test_like(instance: Instance): r"""select '%UU_' ilike '\%uu\_' escape '\' from (values (1))""" ) assert data[0] == [True] + + +def test_select_without_scan(cluster: Cluster): + cluster.deploy(instance_count=2) + i1, i2 = cluster.instances + + cluster.wait_until_instance_has_this_many_active_buckets(i1, 1500) + cluster.wait_until_instance_has_this_many_active_buckets(i2, 1500) + + ddl = i1.sql("create table t (a int primary key)") + assert ddl["row_count"] == 1 + + data = i1.sql("select 1", strip_metadata=False) + assert data["metadata"] == [ + {"name": "col_1", "type": "unsigned"}, + ] + assert data["rows"] == [[1]] + + data = i1.sql("select 1 + 3 as foo", strip_metadata=False) + assert data["metadata"] == [ + {"name": "foo", "type": "unsigned"}, + ] + assert data["rows"] == [[4]] + + # check subquery with global table + data = i1.sql("select (select name from _pico_table where name = 't') as foo") + assert data == [["t"]] + + # check subquery with sharded table + dml = i2.sql("insert into t values (1), (2), (3), (4)") + assert dml["row_count"] == 4 + + data = i1.sql("select (select * from t where a = 3) as bar", strip_metadata=False) + assert data["metadata"] == [ + {"name": "bar", "type": "integer"}, + ] + assert data["rows"] == [[3]] + + # check values + data = i1.sql("select (values (1))") + assert data == [[1]] + + # check recursive + data = i1.sql("select (select 1)") + assert data == [[1]] + + # check usage as a subquery + data = i1.sql("select a from t where a = (select 1)") + assert data == [[1]] + + data = i1.sql( + "select (select 1 as foo) from t where a = (select 1)", strip_metadata=False + ) + assert data["metadata"] == [ + {"name": "col_1", "type": "unsigned"}, + ] + assert data["rows"] == [[1]] + + # check usage with union/except + data = i1.sql("select 1 union all select 1") + assert data == [[1], [1]] + data = i1.sql("select 1 union select 1") + assert data == [[1]] + data = i1.sql("select a from t where a = 1 union select 1") + assert data == [[1]] + data = i1.sql("select 1 except select 2") + assert data == [[1]] + data = i1.sql("select a from t where a = 1 except select 1") + assert data == [] + + # check usage with join + data = i1.sql("select * from t join (select 1) on a = col_1") + assert data == [[1, 1]] + + data = i1.sql("select * from (select 1) join t on a = col_1") + assert data == [[1, 1]] + + # check usage with limit + data = i1.sql("select 1 limit 1") + assert data == [[1]] -- GitLab