Skip to content

Commit

Permalink
feat: implement v1/sql/parse endpoint to parse GreptimeDB's SQL dia…
Browse files Browse the repository at this point in the history
…lect (#5144)

* derive ser/de

Signed-off-by: Ruihang Xia <[email protected]>

* impl method

Signed-off-by: Ruihang Xia <[email protected]>

* fix typo

Signed-off-by: Ruihang Xia <[email protected]>

---------

Signed-off-by: Ruihang Xia <[email protected]>
  • Loading branch information
waynexia authored Dec 11, 2024
1 parent 1a8e77a commit e3f986e
Show file tree
Hide file tree
Showing 24 changed files with 133 additions and 58 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ sysinfo = "0.30"
# on branch v0.44.x
sqlparser = { git = "https://github.com/GreptimeTeam/sqlparser-rs.git", rev = "54a267ac89c09b11c0c88934690530807185d3e7", features = [
"visitor",
"serde",
] }
strum = { version = "0.25", features = ["derive"] }
tempfile = "3"
Expand Down
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
1 change: 1 addition & 0 deletions src/sql/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ itertools.workspace = true
jsonb.workspace = true
lazy_static.workspace = true
regex.workspace = true
serde.workspace = true
serde_json.workspace = true
snafu.workspace = true
sqlparser.workspace = true
Expand Down
3 changes: 2 additions & 1 deletion src/sql/src/statements/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@

use std::fmt::Display;

use serde::{Deserialize, Serialize};
use sqlparser_derive::{Visit, VisitMut};

use crate::ast::Function;

/// `ADMIN` statement to execute some administration commands.
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub enum Admin {
/// Run a admin function.
Func(Function),
Expand Down
11 changes: 6 additions & 5 deletions src/sql/src/statements/alter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ use api::v1;
use common_query::AddColumnLocation;
use datatypes::schema::FulltextOptions;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName, TableConstraint};
use sqlparser_derive::{Visit, VisitMut};

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct AlterTable {
pub table_name: ObjectName,
pub alter_operation: AlterTableOperation,
Expand Down Expand Up @@ -56,7 +57,7 @@ impl Display for AlterTable {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub enum AlterTableOperation {
/// `ADD <table_constraint>`
AddConstraint(TableConstraint),
Expand Down Expand Up @@ -151,7 +152,7 @@ impl Display for AlterTableOperation {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct KeyValueOption {
pub key: String,
pub value: String,
Expand All @@ -166,7 +167,7 @@ impl From<KeyValueOption> for v1::Option {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct AlterDatabase {
pub database_name: ObjectName,
pub alter_operation: AlterDatabaseOperation,
Expand Down Expand Up @@ -197,7 +198,7 @@ impl Display for AlterDatabase {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub enum AlterDatabaseOperation {
SetDatabaseOption { options: Vec<KeyValueOption> },
UnsetDatabaseOption { keys: Vec<String> },
Expand Down
11 changes: 6 additions & 5 deletions src/sql/src/statements/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@

use std::fmt::Display;

use serde::{Deserialize, Serialize};
use sqlparser::ast::ObjectName;
use sqlparser_derive::{Visit, VisitMut};

use crate::statements::OptionMap;

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub enum Copy {
CopyTable(CopyTable),
CopyDatabase(CopyDatabase),
Expand All @@ -34,7 +35,7 @@ impl Display for Copy {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub enum CopyTable {
To(CopyTableArgument),
From(CopyTableArgument),
Expand Down Expand Up @@ -65,7 +66,7 @@ impl Display for CopyTable {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub enum CopyDatabase {
To(CopyDatabaseArgument),
From(CopyDatabaseArgument),
Expand Down Expand Up @@ -96,15 +97,15 @@ impl Display for CopyDatabase {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct CopyDatabaseArgument {
pub database_name: ObjectName,
pub with: OptionMap,
pub connection: OptionMap,
pub location: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct CopyTableArgument {
pub table_name: ObjectName,
pub with: OptionMap,
Expand Down
21 changes: 11 additions & 10 deletions src/sql/src/statements/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::fmt::{Display, Formatter};
use common_catalog::consts::FILE_ENGINE;
use datatypes::schema::FulltextOptions;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use snafu::ResultExt;
use sqlparser::ast::{ColumnOptionDef, DataType, Expr, Query};
use sqlparser_derive::{Visit, VisitMut};
Expand Down Expand Up @@ -58,7 +59,7 @@ fn format_table_constraint(constraints: &[TableConstraint]) -> String {
}

/// Table constraint for create table statement.
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub enum TableConstraint {
/// Primary key constraint.
PrimaryKey { columns: Vec<Ident> },
Expand All @@ -84,7 +85,7 @@ impl Display for TableConstraint {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct CreateTable {
/// Create if not exists
pub if_not_exists: bool,
Expand All @@ -100,7 +101,7 @@ pub struct CreateTable {
}

/// Column definition in `CREATE TABLE` statement.
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct Column {
/// `ColumnDef` from `sqlparser::ast`
pub column_def: ColumnDef,
Expand All @@ -109,7 +110,7 @@ pub struct Column {
}

/// Column extensions for greptimedb dialect.
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Default, Serialize, Deserialize)]
pub struct ColumnExtensions {
/// Fulltext options.
pub fulltext_options: Option<OptionMap>,
Expand Down Expand Up @@ -172,7 +173,7 @@ impl ColumnExtensions {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct Partitions {
pub column_list: Vec<Ident>,
pub exprs: Vec<Expr>,
Expand Down Expand Up @@ -244,7 +245,7 @@ impl Display for CreateTable {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct CreateDatabase {
pub name: ObjectName,
/// Create if not exists
Expand Down Expand Up @@ -278,7 +279,7 @@ impl Display for CreateDatabase {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct CreateExternalTable {
/// Table name
pub name: ObjectName,
Expand Down Expand Up @@ -309,7 +310,7 @@ impl Display for CreateExternalTable {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct CreateTableLike {
/// Table name
pub table_name: ObjectName,
Expand All @@ -325,7 +326,7 @@ impl Display for CreateTableLike {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct CreateFlow {
/// Flow name
pub flow_name: ObjectName,
Expand Down Expand Up @@ -367,7 +368,7 @@ impl Display for CreateFlow {
}

/// Create SQL view statement.
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut, Serialize, Deserialize)]
pub struct CreateView {
/// View name
pub name: ObjectName,
Expand Down
7 changes: 4 additions & 3 deletions src/sql/src/statements/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use std::fmt::Display;

use serde::{Deserialize, Serialize};
use sqlparser::ast::ObjectName;
use sqlparser_derive::{Visit, VisitMut};

Expand All @@ -22,7 +23,7 @@ use super::query::Query;
/// Represents a DECLARE CURSOR statement
///
/// This statement will carry a SQL query
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct DeclareCursor {
pub cursor_name: ObjectName,
pub query: Box<Query>,
Expand All @@ -35,7 +36,7 @@ impl Display for DeclareCursor {
}

/// Represents a FETCH FROM cursor statement
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct FetchCursor {
pub cursor_name: ObjectName,
pub fetch_size: u64,
Expand All @@ -48,7 +49,7 @@ impl Display for FetchCursor {
}

/// Represents a CLOSE cursor statement
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct CloseCursor {
pub cursor_name: ObjectName,
}
Expand Down
3 changes: 2 additions & 1 deletion src/sql/src/statements/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use serde::{Deserialize, Serialize};
use sqlparser::ast::Statement;
use sqlparser_derive::{Visit, VisitMut};

#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct Delete {
pub inner: Statement,
}
3 changes: 2 additions & 1 deletion src/sql/src/statements/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@

use std::fmt::Display;

use serde::{Deserialize, Serialize};
use sqlparser::ast::ObjectName;
use sqlparser_derive::{Visit, VisitMut};

/// SQL structure for `DESCRIBE TABLE`.
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize, Deserialize)]
pub struct DescribeTable {
name: ObjectName,
}
Expand Down
Loading

0 comments on commit e3f986e

Please sign in to comment.