Skip to content

Commit

Permalink
feat(query): support desc procedure (databendlabs#17364)
Browse files Browse the repository at this point in the history
desc procedure p1(int);
----
signature (x)
returns (Int32)
language SQL
body BEGIN RETURN x; END;
  • Loading branch information
TCeason authored Jan 24, 2025
1 parent 1e3f260 commit 742ca86
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 25 deletions.
12 changes: 1 addition & 11 deletions src/query/ast/src/ast/statements/procedure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,22 +158,12 @@ impl Display for DropProcedureStmt {
}
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
pub struct DescProcedureStmt {
pub name: String,
pub args: Vec<TypeName>,
pub name: ProcedureIdentity,
}

impl Display for DescProcedureStmt {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "DESCRIBE PROCEDURE {}", self.name)?;

if self.args.is_empty() {
write!(f, "()")?;
} else {
write!(f, "(")?;
write_comma_separated_list(f, self.args.clone())?;
write!(f, ")")?;
}

Ok(())
}
}
Expand Down
13 changes: 11 additions & 2 deletions src/query/ast/src/parser/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2392,8 +2392,17 @@ pub fn statement_body(i: Input) -> IResult<Statement> {
|(_, _, name, args)| {
// TODO: modify to ProcedureIdentify
Statement::DescProcedure(DescProcedureStmt {
name: name.to_string(),
args,
name: ProcedureIdentity {
name: name.to_string(),
args_type: if args.is_empty() {
"".to_string()
} else {
args.iter()
.map(|arg| arg.to_string())
.collect::<Vec<String>>()
.join(",")
},
},
})
},
);
Expand Down
17 changes: 9 additions & 8 deletions src/query/ast/tests/it/testdata/stmt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24722,24 +24722,25 @@ DESCRIBE PROCEDURE p1()
---------- AST ------------
DescProcedure(
DescProcedureStmt {
name: "p1",
args: [],
name: ProcedureIdentity {
name: "p1",
args_type: "",
},
},
)


---------- Input ----------
describe PROCEDURE p1(string, timestamp)
---------- Output ---------
DESCRIBE PROCEDURE p1(STRING, TIMESTAMP)
DESCRIBE PROCEDURE p1(STRING,TIMESTAMP)
---------- AST ------------
DescProcedure(
DescProcedureStmt {
name: "p1",
args: [
String,
Timestamp,
],
name: ProcedureIdentity {
name: "p1",
args_type: "STRING,TIMESTAMP",
},
},
)

Expand Down
2 changes: 1 addition & 1 deletion src/query/management/src/procedure/procedure_mgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl ProcedureMgr {
Ok(dropped)
}

#[fastrace::trace]
//#[fastrace::trace]
pub async fn get_procedure(
&self,
req: &GetProcedureReq,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,7 @@ impl AccessChecker for PrivilegeAccess {
| Plan::CallProcedure(_)
| Plan::CreateProcedure(_)
| Plan::DropProcedure(_)
| Plan::DescProcedure(_)
/*| Plan::ShowCreateProcedure(_)
| Plan::RenameProcedure(_)*/ => {
self.validate_access(&GrantObject::Global, UserPrivilegeType::Super, false, false)
Expand Down
3 changes: 3 additions & 0 deletions src/query/service/src/interpreters/interpreter_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,9 @@ impl InterpreterFactory {
ctx,
*p.clone(),
)?)),
Plan::DescProcedure(p) => {
Ok(Arc::new(DescProcedureInterpreter::try_create(*p.clone())?))
}
Plan::CallProcedure(p) => Ok(Arc::new(CallProcedureInterpreter::try_create(
ctx,
*p.clone(),
Expand Down
80 changes: 80 additions & 0 deletions src/query/service/src/interpreters/interpreter_procedure_desc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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 databend_common_exception::ErrorCode;
use databend_common_exception::Result;
use databend_common_expression::types::StringType;
use databend_common_expression::DataBlock;
use databend_common_expression::FromData;
use databend_common_meta_app::principal::GetProcedureReq;
use databend_common_sql::plans::DescProcedurePlan;
use databend_common_users::UserApiProvider;
use itertools::Itertools;

use crate::interpreters::Interpreter;
use crate::pipelines::PipelineBuildResult;

#[derive(Debug)]
pub struct DescProcedureInterpreter {
pub(crate) plan: DescProcedurePlan,
}

impl DescProcedureInterpreter {
pub fn try_create(plan: DescProcedurePlan) -> Result<Self> {
Ok(DescProcedureInterpreter { plan })
}
}

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

fn is_ddl(&self) -> bool {
false
}

#[fastrace::trace]
#[async_backtrace::framed]
async fn execute2(&self) -> Result<PipelineBuildResult> {
let tenant = self.plan.tenant.clone();

let req: GetProcedureReq = self.plan.clone().into();
let procedure = UserApiProvider::instance()
.procedure_api(&tenant)
.get_procedure(&req)
.await?;

if let Some(procedure) = procedure {
let script = format!("{}", procedure.procedure_meta.script);
let returns = format!(
"({})",
procedure.procedure_meta.return_types.iter().join(",")
);
let signature = format!("({})", procedure.procedure_meta.arg_names.iter().join(","));
let language = procedure.procedure_meta.procedure_language;

PipelineBuildResult::from_blocks(vec![DataBlock::new_from_columns(vec![
StringType::from_data(vec!["signature", "returns", "language", "body"]),
StringType::from_data(vec![signature, returns, language, script]),
])])
} else {
return Err(ErrorCode::UnknownProcedure(format!(
"Unknown procedure {}",
self.plan.name.procedure_name()
)));
}
}
}
2 changes: 2 additions & 0 deletions src/query/service/src/interpreters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ mod interpreter_privilege_grant;
mod interpreter_privilege_revoke;
mod interpreter_procedure_call;
mod interpreter_procedure_create;
mod interpreter_procedure_desc;
mod interpreter_procedure_drop;
mod interpreter_rename_warehouse;
mod interpreter_rename_warehouse_cluster;
Expand Down Expand Up @@ -204,6 +205,7 @@ pub use interpreter_password_policy_desc::DescPasswordPolicyInterpreter;
pub use interpreter_password_policy_drop::DropPasswordPolicyInterpreter;
pub use interpreter_privilege_grant::GrantPrivilegeInterpreter;
pub use interpreter_privilege_revoke::RevokePrivilegeInterpreter;
pub use interpreter_procedure_desc::DescProcedureInterpreter;
pub use interpreter_replace::ReplaceInterpreter;
pub use interpreter_role_create::CreateRoleInterpreter;
pub use interpreter_role_drop::DropRoleInterpreter;
Expand Down
11 changes: 9 additions & 2 deletions src/query/sql/src/planner/binder/ddl/procedure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use databend_common_users::UserApiProvider;
use crate::binder::show::get_show_options;
use crate::plans::CallProcedurePlan;
use crate::plans::CreateProcedurePlan;
use crate::plans::DescProcedurePlan;
use crate::plans::DropProcedurePlan;
use crate::plans::ExecuteImmediatePlan;
use crate::plans::Plan;
Expand Down Expand Up @@ -97,8 +98,14 @@ impl Binder {
})))
}

pub async fn bind_desc_procedure(&mut self, _stmt: &DescProcedureStmt) -> Result<Plan> {
todo!()
pub async fn bind_desc_procedure(&mut self, stmt: &DescProcedureStmt) -> Result<Plan> {
let DescProcedureStmt { name } = stmt;

let tenant = self.ctx.get_tenant();
Ok(Plan::DescProcedure(Box::new(DescProcedurePlan {
tenant: tenant.to_owned(),
name: ProcedureNameIdent::new(tenant, ProcedureIdentity::from(name.clone())),
})))
}

pub async fn bind_show_procedures(
Expand Down
1 change: 1 addition & 0 deletions src/query/sql/src/planner/format/display_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ impl Plan {
Plan::ExecuteImmediate(_) => Ok("ExecuteImmediate".to_string()),
Plan::CreateProcedure(_) => Ok("CreateProcedure".to_string()),
Plan::DropProcedure(_) => Ok("DropProcedure".to_string()),
Plan::DescProcedure(_) => Ok("DescProcedure".to_string()),
Plan::CallProcedure(_) => Ok("CallProcedure".to_string()),
// Plan::ShowCreateProcedure(_) => Ok("ShowCreateProcedure".to_string()),
// Plan::RenameProcedure(_) => Ok("ProcedureDatabase".to_string()),
Expand Down
30 changes: 30 additions & 0 deletions src/query/sql/src/planner/plans/ddl/procedure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use databend_common_expression::DataSchemaRef;
use databend_common_expression::DataSchemaRefExt;
use databend_common_meta_app::principal::CreateProcedureReq;
use databend_common_meta_app::principal::DropProcedureReq;
use databend_common_meta_app::principal::GetProcedureReq;
use databend_common_meta_app::principal::ProcedureMeta;
use databend_common_meta_app::principal::ProcedureNameIdent;
use databend_common_meta_app::schema::CreateOption;
Expand Down Expand Up @@ -96,3 +97,32 @@ impl CallProcedurePlan {
DataSchemaRefExt::create(vec![DataField::new("Result", DataType::String)])
}
}

#[derive(Debug, Clone)]
pub struct DescProcedurePlan {
pub tenant: Tenant,
pub name: ProcedureNameIdent,
}

impl DescProcedurePlan {
pub fn schema(&self) -> DataSchemaRef {
DataSchemaRefExt::create(vec![
DataField::new("Property", DataType::String),
DataField::new("Value", DataType::String),
])
}
}

impl From<DescProcedurePlan> for GetProcedureReq {
fn from(p: DescProcedurePlan) -> Self {
GetProcedureReq { inner: p.name }
}
}

impl From<&DescProcedurePlan> for GetProcedureReq {
fn from(p: &DescProcedurePlan) -> Self {
GetProcedureReq {
inner: p.name.clone(),
}
}
}
4 changes: 3 additions & 1 deletion src/query/sql/src/planner/plans/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ use crate::plans::DescDatamaskPolicyPlan;
use crate::plans::DescNetworkPolicyPlan;
use crate::plans::DescNotificationPlan;
use crate::plans::DescPasswordPolicyPlan;
use crate::plans::DescProcedurePlan;
use crate::plans::DescUserPlan;
use crate::plans::DescribeTablePlan;
use crate::plans::DescribeTaskPlan;
Expand Down Expand Up @@ -393,6 +394,7 @@ pub enum Plan {
ExecuteImmediate(Box<ExecuteImmediatePlan>),
// ShowCreateProcedure(Box<ShowCreateProcedurePlan>),
DropProcedure(Box<DropProcedurePlan>),
DescProcedure(Box<DescProcedurePlan>),
CreateProcedure(Box<CreateProcedurePlan>),
CallProcedure(Box<CallProcedurePlan>),
// RenameProcedure(Box<RenameProcedurePlan>),
Expand Down Expand Up @@ -539,7 +541,7 @@ impl Plan {
DataField::new("cluster", DataType::String),
DataField::new("version", DataType::String),
]),

Plan::DescProcedure(plan) => plan.schema(),
_ => Arc::new(DataSchema::empty()),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
statement ok
set global enable_experimental_procedure=1;

statement ok
drop procedure if exists p1(int);

statement ok
CREATE PROCEDURE if not exists p1(x int) RETURNS int not null LANGUAGE SQL COMMENT='test' AS $$
BEGIN
RETURN x;
END;
$$;

query T
desc procedure p1(int);
----
signature (x)
returns (Int32)
language SQL
body BEGIN RETURN x; END;

statement ok
drop procedure if exists p1();

Expand Down Expand Up @@ -105,6 +123,7 @@ query T
select name, arguments from system.procedures where name = 'p1';
----
p1 p1() RETURN (Int32)
p1 p1(Int32) RETURN (Int32)
p1 p1(UInt8,UInt8) RETURN (Int32)

statement ok
Expand All @@ -113,6 +132,9 @@ drop procedure p1();
statement ok
drop procedure p1(UInt8, UInt8);

statement ok
drop procedure p1(int);

query T
select count(name) from system.procedures
----
Expand Down

0 comments on commit 742ca86

Please sign in to comment.