Skip to content

Commit 0a36127

Browse files
committed
feat: impl UDTF Args replace
1 parent c53abfb commit 0a36127

File tree

2 files changed

+69
-21
lines changed

2 files changed

+69
-21
lines changed

src/query/sql/src/planner/binder/bind_table_reference/bind_table_function.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@ use databend_common_expression::FunctionKind;
3636
use databend_common_expression::Scalar;
3737
use databend_common_functions::BUILTIN_FUNCTIONS;
3838
use databend_common_meta_app::principal::UDFDefinition;
39+
use databend_common_meta_app::principal::UDTF;
3940
use databend_common_storages_result_cache::ResultCacheMetaManager;
4041
use databend_common_storages_result_cache::ResultScan;
4142
use databend_common_users::UserApiProvider;
43+
use derive_visitor::DriveMut;
44+
use derive_visitor::VisitorMut;
45+
use itertools::Itertools;
4246

4347
use crate::binder::scalar::ScalarBinder;
4448
use crate::binder::table_args::bind_table_args;
@@ -70,6 +74,37 @@ impl Binder {
7074
alias: &Option<TableAlias>,
7175
sample: &Option<SampleConfig>,
7276
) -> Result<(SExpr, BindContext)> {
77+
#[derive(VisitorMut)]
78+
#[visitor(Expr(enter))]
79+
struct UDTFArgVisitor<'a> {
80+
udtf: &'a UDTF,
81+
table_args: &'a TableArgs,
82+
}
83+
84+
impl UDTFArgVisitor<'_> {
85+
fn enter_expr(&mut self, expr: &mut Expr) {
86+
if let Expr::ColumnRef { span, column } = expr {
87+
if column.database.is_some() || column.table.is_some() {
88+
return;
89+
}
90+
assert_eq!(self.udtf.arg_types.len(), self.table_args.positioned.len());
91+
let Some((pos, (_, _ty))) = self
92+
.udtf
93+
.arg_types
94+
.iter()
95+
.find_position(|(name, _)| name == column.column.name())
96+
else {
97+
return;
98+
};
99+
100+
*expr = Expr::Literal {
101+
span: *span,
102+
value: Literal::String(self.table_args.positioned[pos].to_string()),
103+
}
104+
}
105+
}
106+
}
107+
73108
let func_name = normalize_identifier(name, &self.name_resolution_ctx);
74109

75110
if BUILTIN_FUNCTIONS
@@ -142,30 +177,32 @@ impl Binder {
142177
.await?
143178
.map(|udf| udf.definition)
144179
{
145-
let mut sql = udtf.sql;
146-
147-
for (name, arg) in table_args.named.iter() {
148-
// FIXME: Parameter substitution
149-
let Some((_, _ty)) =
150-
udtf.arg_types.iter().find(|(arg_name, _)| arg_name == name)
151-
else {
152-
return Err(ErrorCode::InvalidArgument(format!(
153-
"Function '{func_name}' does not have a parameter named '{name}'"
154-
)));
155-
};
180+
let mut stmt = Planner::new(self.ctx.clone())
181+
.parse_sql(&udtf.sql)?
182+
.statement;
156183

157-
sql = sql.replace(name, &arg.to_string());
184+
if udtf.arg_types.len() != table_args.positioned.len() {
185+
return Err(ErrorCode::UDFSchemaMismatch(format!(
186+
"UDTF '{}' argument types length {} does not match input arguments length {}",
187+
func_name,
188+
udtf.arg_types.len(),
189+
table_args.positioned.len()
190+
)));
158191
}
159-
let mut planner = Planner::new(self.ctx.clone());
160-
let (_, extras) = planner.plan_sql(&sql).await?;
192+
let mut visitor = UDTFArgVisitor {
193+
udtf: &udtf,
194+
table_args: &table_args,
195+
};
196+
stmt.drive_mut(&mut visitor);
197+
161198
let binder = Binder::new(
162199
self.ctx.clone(),
163200
CatalogManager::instance(),
164201
self.name_resolution_ctx.clone(),
165202
self.metadata.clone(),
166203
)
167204
.with_subquery_executor(self.subquery_executor.clone());
168-
let plan = binder.bind(&extras.statement).await?;
205+
let plan = binder.bind(&stmt).await?;
169206

170207
let Plan::Query {
171208
s_expr,
@@ -182,7 +219,8 @@ impl Binder {
182219

183220
if udtf.return_types.len() != bind_context.columns.len() {
184221
return Err(ErrorCode::UDFSchemaMismatch(format!(
185-
"return types length {} does not match output columns length {}",
222+
"UDTF '{}' return types length {} does not match output columns length {}",
223+
func_name,
186224
udtf.return_types.len(),
187225
bind_context.columns.len()
188226
)));

tests/sqllogictests/suites/base/03_common/03_0013_select_udf.test

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ statement ok
213213
insert into t1 values(0), (1);
214214

215215
statement ok
216-
create function scan_t1 () RETURNS TABLE (c1_string string) as $$ select * from t1 $$;
216+
create or replace function scan_t1 () RETURNS TABLE (c1_string string) as $$ select * from t1 $$;
217217

218218
query T
219219
select * from scan_t1();
@@ -222,13 +222,23 @@ select * from scan_t1();
222222
1
223223

224224
statement ok
225-
create function invalid_udtf_0 () RETURNS TABLE () as $$ select * from t1 $$;
225+
create or replace function filter_t1 (arg0 int) RETURNS TABLE (c1_string string) as $$ select * from t1 where c1 = arg0 $$;
226+
227+
query T
228+
select * from filter_t1(0);
229+
----
230+
0
231+
232+
query T
233+
select * from filter_t1(1);
234+
----
235+
1
226236

227237
statement error
228-
select * from invalid_udtf_0();
238+
select * from filter_t1();
229239

230240
statement ok
231-
create function invalid_udtf_1 () RETURNS TABLE (c1_string string, c2 int) as $$ select * from t1 $$;
241+
create or replace function invalid_udtf_0 () RETURNS TABLE (c1_string string, c2 int) as $$ select * from t1 $$;
232242

233243
statement error
234-
select * from invalid_udtf_1();
244+
select * from invalid_udtf_0();

0 commit comments

Comments
 (0)