Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE-4860: fix empty query #4894

Merged
merged 1 commit into from
Apr 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions query/src/interpreters/interpreter_empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2022 Datafuse Labs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use common_datavalues::prelude::*;
use common_exception::Result;
use common_planners::EmptyPlan;
use common_streams::DataBlockStream;
use common_streams::SendableDataBlockStream;

use crate::interpreters::Interpreter;
use crate::interpreters::InterpreterPtr;
use crate::sessions::QueryContext;

// EmptyInterpreter is a Empty interpreter to execute nothing.
// Such as the query '/*!40101*/', it makes the front-end (e.g. MySQL handler) no need check the EmptyPlan or not.
pub struct EmptyInterpreter {}

impl EmptyInterpreter {
pub fn try_create(_ctx: Arc<QueryContext>, _plan: EmptyPlan) -> Result<InterpreterPtr> {
Ok(Arc::new(EmptyInterpreter {}))
}
}

#[async_trait::async_trait]
impl Interpreter for EmptyInterpreter {
fn name(&self) -> &str {
"EmptyInterpreter"
}

async fn execute(
&self,
_input_stream: Option<SendableDataBlockStream>,
) -> Result<SendableDataBlockStream> {
Ok(Box::pin(DataBlockStream::create(
Arc::new(DataSchema::empty()),
None,
vec![],
)))
}
}
2 changes: 2 additions & 0 deletions query/src/interpreters/interpreter_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use crate::interpreters::DropTableInterpreter;
use crate::interpreters::DropUserInterpreter;
use crate::interpreters::DropUserUDFInterpreter;
use crate::interpreters::DropViewInterpreter;
use crate::interpreters::EmptyInterpreter;
use crate::interpreters::ExplainInterpreter;
use crate::interpreters::GrantPrivilegeInterpreter;
use crate::interpreters::GrantRoleInterpreter;
Expand Down Expand Up @@ -172,6 +173,7 @@ impl InterpreterFactory {
PlanNode::UseDatabase(v) => UseDatabaseInterpreter::try_create(ctx_clone, v),
PlanNode::Kill(v) => KillInterpreter::try_create(ctx_clone, v),
PlanNode::SetVariable(v) => SettingInterpreter::try_create(ctx_clone, v),
PlanNode::Empty(v) => EmptyInterpreter::try_create(ctx_clone, v),

_ => Result::Err(ErrorCode::UnknownTypeOfQuery(format!(
"Can't get the interpreter by plan:{}",
Expand Down
2 changes: 2 additions & 0 deletions query/src/interpreters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod interpreter_copy;
mod interpreter_database_create;
mod interpreter_database_drop;
mod interpreter_database_show_create;
mod interpreter_empty;
mod interpreter_explain;
mod interpreter_factory;
mod interpreter_factory_interceptor;
Expand Down Expand Up @@ -76,6 +77,7 @@ pub use interpreter_copy::CopyInterpreter;
pub use interpreter_database_create::CreateDatabaseInterpreter;
pub use interpreter_database_drop::DropDatabaseInterpreter;
pub use interpreter_database_show_create::ShowCreateDatabaseInterpreter;
pub use interpreter_empty::EmptyInterpreter;
pub use interpreter_explain::ExplainInterpreter;
pub use interpreter_factory::InterpreterFactory;
pub use interpreter_factory_interceptor::InterceptorInterpreter;
Expand Down
3 changes: 2 additions & 1 deletion query/src/sql/plan_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::sync::Arc;

use common_exception::ErrorCode;
use common_exception::Result;
use common_planners::EmptyPlan;
use common_planners::ExplainPlan;
use common_planners::Expression;
use common_planners::PlanBuilder;
Expand Down Expand Up @@ -54,7 +55,7 @@ impl PlanParser {
ctx: Arc<QueryContext>,
) -> Result<PlanNode> {
if statements.is_empty() {
return Err(ErrorCode::SyntaxException("Empty query"));
return Ok(PlanNode::Empty(EmptyPlan::create()));
} else if statements.len() > 1 {
return Err(ErrorCode::SyntaxException("Only support single query"));
}
Expand Down
60 changes: 60 additions & 0 deletions query/tests/it/interpreters/interpreter_empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2021 Datafuse Labs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use common_base::tokio;
use common_exception::Result;
use databend_query::interpreters::*;
use databend_query::sql::*;
use futures::TryStreamExt;
use pretty_assertions::assert_eq;

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_empty_interpreter() -> Result<()> {
common_tracing::init_default_ut_tracing();
let ctx = crate::tests::create_query_context().await?;

{
let query = "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */";
let plan = PlanParser::parse(ctx.clone(), query).await?;
let executor = InterpreterFactory::get(ctx.clone(), plan)?;
assert_eq!(executor.name(), "EmptyInterpreter");

let stream = executor.execute(None).await?;
let result = stream.try_collect::<Vec<_>>().await;
assert!(result.is_ok())
}

{
let query = "/*!40101*/select number from numbers_mt(1)";
let plan = PlanParser::parse(ctx.clone(), query).await?;
let executor = InterpreterFactory::get(ctx.clone(), plan)?;
assert_eq!(executor.name(), "SelectInterpreter");

let stream = executor.execute(None).await?;
let result = stream.try_collect::<Vec<_>>().await?;
let block = &result[0];
assert_eq!(block.num_columns(), 1);

let expected = vec![
"+--------+",
"| number |",
"+--------+",
"| 0 |",
"+--------+",
];
common_datablocks::assert_blocks_sorted_eq(expected, result.as_slice());
}

Ok(())
}
1 change: 1 addition & 0 deletions query/tests/it/interpreters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod interpreter_call;
mod interpreter_database_create;
mod interpreter_database_drop;
mod interpreter_database_show_create;
mod interpreter_empty;
mod interpreter_explain;
mod interpreter_factory_interceptor;
mod interpreter_insert;
Expand Down
12 changes: 6 additions & 6 deletions query/tests/it/servers/http/clickhouse_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ macro_rules! assert_ok {
async fn test_select() -> PoemResult<()> {
let server = Server::new();

{
let (status, body) = server.get("").await;
assert_eq!(status, StatusCode::BAD_REQUEST);
assert_error!(body, "Empty query");
}

{
let (status, body) = server.get("bad sql").await;
assert_eq!(status, StatusCode::BAD_REQUEST);
Expand All @@ -69,6 +63,12 @@ async fn test_select() -> PoemResult<()> {
assert_error!(body, "sql parser error");
}

{
let (status, body) = server.get("").await;
cadl marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(status, StatusCode::OK);
assert_eq!(&body, "");
}

{
let (status, body) = server.get("select 1").await;
assert_eq!(status, StatusCode::OK);
Expand Down
3 changes: 3 additions & 0 deletions tests/suites/0_stateless/03_dml/03_0019_select_empty.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
0
1
0
3 changes: 3 additions & 0 deletions tests/suites/0_stateless/03_dml/03_0019_select_empty.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*!40101*/select number from numbers_mt(2);
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101*/select number from numbers_mt(1);