Skip to content

Commit

Permalink
impl method
Browse files Browse the repository at this point in the history
Signed-off-by: Ruihang Xia <[email protected]>
  • Loading branch information
waynexia committed Dec 11, 2024
1 parent fb75e5b commit 63fada0
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 2 deletions.
10 changes: 9 additions & 1 deletion src/servers/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ pub enum Error {
location: Location,
},

#[snafu(display("Failed to parse query"))]
FailedToParseQuery {
#[snafu(implicit)]
location: Location,
source: sql::error::Error,
},

#[snafu(display("Failed to parse InfluxDB line protocol"))]
InfluxdbLineProtocol {
#[snafu(implicit)]
Expand Down Expand Up @@ -651,7 +658,8 @@ impl ErrorExt for Error {
| OpenTelemetryLog { .. }
| UnsupportedJsonDataTypeForTag { .. }
| InvalidTableName { .. }
| PrepareStatementNotFound { .. } => StatusCode::InvalidArguments,
| PrepareStatementNotFound { .. }
| FailedToParseQuery { .. } => StatusCode::InvalidArguments,

Catalog { source, .. } => source.status_code(),
RowWriter { source, .. } => source.status_code(),
Expand Down
4 changes: 4 additions & 0 deletions src/servers/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ impl HttpServer {
fn route_sql<S>(api_state: ApiState) -> Router<S> {
Router::new()
.route("/sql", routing::get(handler::sql).post(handler::sql))
.route(
"/sql/parse",
routing::get(handler::sql_parse).post(handler::sql_parse),
)
.route(
"/promql",
routing::get(handler::promql).post(handler::promql),
Expand Down
28 changes: 27 additions & 1 deletion src/servers/src/http/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ use query::parser::{PromQuery, DEFAULT_LOOKBACK_STRING};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use session::context::{Channel, QueryContext, QueryContextRef};
use snafu::ResultExt;
use sql::dialect::GreptimeDbDialect;
use sql::parser::{ParseOptions, ParserContext};
use sql::statements::statement::Statement;

use super::header::collect_plan_metrics;
use crate::error::{FailedToParseQuerySnafu, InvalidQuerySnafu, Result};
use crate::http::result::arrow_result::ArrowResponse;
use crate::http::result::csv_result::CsvResponse;
use crate::http::result::error_result::ErrorResponse;
Expand Down Expand Up @@ -146,10 +151,31 @@ pub async fn sql(
resp.with_execution_time(start.elapsed().as_millis() as u64)
}

/// Handler to parse sql
#[axum_macros::debug_handler]
#[tracing::instrument(skip_all, fields(protocol = "http", request_type = "sql"))]
pub async fn sql_parse(
Query(query_params): Query<SqlQuery>,
Form(form_params): Form<SqlQuery>,
) -> Result<Json<Vec<Statement>>> {
let Some(sql) = query_params.sql.or(form_params.sql) else {
return InvalidQuerySnafu {
reason: "sql parameter is required.",
}
.fail();
};

let stmts =
ParserContext::create_with_dialect(&sql, &GreptimeDbDialect {}, ParseOptions::default())
.context(FailedToParseQuerySnafu)?;

Ok(stmts.into())
}

/// Create a response from query result
pub async fn from_output(
outputs: Vec<crate::error::Result<Output>>,
) -> Result<(Vec<GreptimeQueryOutput>, HashMap<String, Value>), ErrorResponse> {
) -> std::result::Result<(Vec<GreptimeQueryOutput>, HashMap<String, Value>), ErrorResponse> {
// TODO(sunng87): this api response structure cannot represent error well.
// It hides successful execution results from error response
let mut results = Vec::with_capacity(outputs.len());
Expand Down
13 changes: 13 additions & 0 deletions tests-integration/tests/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use servers::http::result::influxdb_result_v1::{InfluxdbOutput, InfluxdbV1Respon
use servers::http::test_helpers::{TestClient, TestResponse};
use servers::http::GreptimeQueryOutput;
use servers::prom_store;
use sql::statements::statement::Statement;
use tests_integration::test_util::{
setup_test_http_app, setup_test_http_app_with_frontend,
setup_test_http_app_with_frontend_and_user_provider, setup_test_prom_app_with_frontend,
Expand Down Expand Up @@ -361,6 +362,18 @@ pub async fn test_sql_api(store_type: StorageType) {
let body = serde_json::from_str::<ErrorResponse>(&res.text().await).unwrap();
assert_eq!(body.code(), ErrorCode::DatabaseNotFound as u32);

// test parse method
let res = client.get("/v1/sql/parse?sql=desc table t").send().await;
assert_eq!(res.status(), StatusCode::OK);
let body = serde_json::from_str::<Vec<Statement>>(&res.text().await).unwrap();
assert_eq!(
body,
serde_json::from_value::<Vec<Statement>>(json!(
[{"DescribeTable":{"name":[{"value":"t","quote_style":null}]}}]
))
.unwrap()
);

// test timezone header
let res = client
.get("/v1/sql?&sql=show variables system_time_zone")
Expand Down

0 comments on commit 63fada0

Please sign in to comment.