1use std::collections::{HashMap, HashSet};
16use std::str::FromStr;
17use std::sync::Arc;
18
19use anyhow::Context;
20use itertools::Itertools;
21use risingwave_common::acl::AclMode;
22use risingwave_common::bail_not_implemented;
23use risingwave_common::catalog::INFORMATION_SCHEMA_SCHEMA_NAME;
24use risingwave_common::secret::LocalSecretManager;
25use risingwave_common::types::{DataType, MapType, StructType};
26use risingwave_common::util::iter_util::ZipEqFast;
27use risingwave_expr::aggregate::AggType;
28use risingwave_expr::window_function::WindowFuncKind;
29use risingwave_sqlparser::ast::{
30 self, Expr as AstExpr, Function, FunctionArg, FunctionArgExpr, FunctionArgList, Ident,
31 OrderByExpr, SecretRefAsType, Statement, Window,
32};
33use risingwave_sqlparser::parser::Parser;
34
35use crate::binder::Binder;
36use crate::binder::bind_context::Clause;
37use crate::catalog::OwnedByUserCatalog;
38use crate::catalog::function_catalog::FunctionCatalog;
39use crate::error::{ErrorCode, Result, RwError};
40use crate::expr::{
41 Expr, ExprImpl, ExprType, FunctionCall, FunctionCallWithLambda, InputRef, TableFunction,
42 TableFunctionType, UserDefinedFunction, expr_impl_to_string_fn,
43};
44use crate::handler::privilege::ObjectCheckItem;
45
46mod aggregate;
47mod builtin_scalar;
48mod window;
49
50const SYS_FUNCTION_WITHOUT_ARGS: &[&str] = &[
52 "session_user",
53 "user",
54 "current_user",
55 "current_role",
56 "current_catalog",
57 "current_schema",
58 "current_timestamp",
59];
60
61const INLINE_QUERY_ARG_LEN: usize = 6;
62const CDC_SOURCE_QUERY_ARG_LEN: usize = 2;
63
64pub(super) fn is_sys_function_without_args(ident: &Ident) -> bool {
65 SYS_FUNCTION_WITHOUT_ARGS
66 .iter()
67 .any(|e| ident.real_value().as_str() == *e && ident.quote_style().is_none())
68}
69
70macro_rules! reject_syntax {
71 ($pred:expr, $msg:expr) => {
72 if $pred {
73 return Err(ErrorCode::InvalidInputSyntax($msg.to_string()).into());
74 }
75 };
76
77 ($pred:expr, $fmt:expr, $($arg:tt)*) => {
78 if $pred {
79 return Err(ErrorCode::InvalidInputSyntax(
80 format!($fmt, $($arg)*)
81 ).into());
82 }
83 };
84}
85
86impl Binder {
87 fn bind_postgres_or_mysql_query_args(
88 &self,
89 schema_name: Option<&str>,
90 args: Vec<ExprImpl>,
91 expected_connector_name: &str,
92 ) -> Result<Vec<ExprImpl>> {
93 match args.len() {
94 INLINE_QUERY_ARG_LEN => {
95 let mut cast_args = Vec::with_capacity(INLINE_QUERY_ARG_LEN);
96 for arg in args {
97 cast_args.push(arg.cast_implicit(&DataType::Varchar)?);
98 }
99 Ok(cast_args)
100 }
101 CDC_SOURCE_QUERY_ARG_LEN => {
102 let source_name = expr_impl_to_string_fn(&args[0])?;
103 let source_catalog = self
104 .catalog
105 .get_source_by_name(
106 &self.db_name,
107 self.bind_schema_path(schema_name),
108 &source_name,
109 )?
110 .0;
111
112 self.check_privilege(
113 ObjectCheckItem::new(
114 source_catalog.owner,
115 AclMode::Select,
116 source_catalog.name.clone(),
117 source_catalog.id,
118 ),
119 source_catalog.database_id,
120 )?;
121
122 if !source_catalog
123 .connector_name()
124 .eq_ignore_ascii_case(expected_connector_name)
125 {
126 return Err(ErrorCode::BindError(format!(
127 "TVF function only accepts `mysql-cdc` and `postgres-cdc` source. Expected: {}, but got: {}",
128 expected_connector_name,
129 source_catalog.connector_name()
130 ))
131 .into());
132 }
133
134 let (props, secret_refs) = source_catalog.with_properties.clone().into_parts();
135 let secret_resolved =
136 LocalSecretManager::global().fill_secrets(props, secret_refs)?;
137
138 let mut args_vec = vec![
139 ExprImpl::literal_varchar(secret_resolved["hostname"].clone()),
140 ExprImpl::literal_varchar(secret_resolved["port"].clone()),
141 ExprImpl::literal_varchar(secret_resolved["username"].clone()),
142 ExprImpl::literal_varchar(secret_resolved["password"].clone()),
143 ExprImpl::literal_varchar(secret_resolved["database.name"].clone()),
144 args[1].clone().cast_implicit(&DataType::Varchar)?,
145 ];
146
147 if expected_connector_name.eq_ignore_ascii_case("postgres-cdc") {
148 args_vec.push(ExprImpl::literal_varchar(
149 secret_resolved.get("ssl.mode").cloned().unwrap_or_default(),
150 ));
151 args_vec.push(ExprImpl::literal_varchar(
152 secret_resolved
153 .get("ssl.root.cert")
154 .cloned()
155 .unwrap_or_default(),
156 ));
157 }
158
159 Ok(args_vec)
160 }
161 _ => Err(ErrorCode::BindError("postgres_query function and mysql_query function accept either 2 arguments: (cdc_source_name varchar, query varchar) or 6 arguments: (hostname varchar, port varchar, username varchar, password varchar, database_name varchar, query varchar)".to_owned()).into()),
162 }
163 }
164
165 pub(in crate::binder) fn bind_function(
166 &mut self,
167 Function {
168 scalar_as_agg,
169 name,
170 arg_list,
171 within_group,
172 filter,
173 over,
174 }: &Function,
175 ) -> Result<ExprImpl> {
176 let (schema_name, func_name) = match name.0.as_slice() {
177 [name] => (None, name.real_value()),
178 [schema, name] => {
179 let schema_name = schema.real_value();
180 let func_name = if schema_name == INFORMATION_SCHEMA_SCHEMA_NAME {
181 let function_name = name.real_value();
185 if function_name != "_pg_expandarray" {
186 bail_not_implemented!(
187 issue = 12422,
188 "Unsupported function name under schema: {}",
189 schema_name
190 );
191 }
192 function_name
193 } else {
194 name.real_value()
195 };
196 (Some(schema_name), func_name)
197 }
198 [database, schema, name] => {
199 let database_name = database.real_value();
201 if database_name != self.db_name {
202 return Err(ErrorCode::BindError(format!(
203 "Cross-database function call is not supported: {}",
204 name
205 ))
206 .into());
207 }
208 let schema_name = schema.real_value();
209 let func_name = name.real_value();
210 (Some(schema_name), func_name)
211 }
212 _ => bail_not_implemented!(issue = 112, "qualified function {}", name),
213 };
214
215 if func_name == "obj_description" || func_name == "col_description" {
222 return Ok(ExprImpl::literal_varchar("".to_owned()));
223 }
224
225 if func_name == "array_transform" || func_name == "map_filter" {
227 return self.validate_and_bind_special_function_params(
228 &func_name,
229 *scalar_as_agg,
230 arg_list,
231 within_group.as_deref(),
232 filter.as_deref(),
233 over.as_ref(),
234 );
235 }
236
237 let has_secret_ref_arg = arg_list.args.iter().any(|arg| {
240 matches!(
241 arg,
242 FunctionArg::Unnamed(FunctionArgExpr::SecretRef(_))
243 | FunctionArg::Named {
244 arg: FunctionArgExpr::SecretRef(_),
245 ..
246 }
247 )
248 });
249
250 if has_secret_ref_arg {
253 let has_udf_candidate = self
254 .catalog
255 .get_functions_by_name(
256 &self.db_name,
257 self.bind_schema_path(schema_name.as_deref()),
258 &func_name,
259 )
260 .map(|(funcs, _)| !funcs.is_empty())
261 .unwrap_or(false);
262 if !has_udf_candidate {
263 return Err(ErrorCode::InvalidInputSyntax(
264 "secret reference is only allowed in user-defined function arguments"
265 .to_owned(),
266 )
267 .into());
268 }
269 }
270
271 let bind_arg = if func_name.eq_ignore_ascii_case("jsonb_agg") {
272 Self::bind_jsonb_agg_arg
273 } else {
274 Self::bind_function_arg
275 };
276 let mut args: Vec<ExprImpl> = arg_list
277 .args
278 .iter()
279 .map(|arg| bind_arg(self, arg))
280 .flatten_ok()
281 .try_collect()?;
282
283 let mut referred_udfs = HashSet::new();
284 let mut is_udf_call = false;
285
286 let wrapped_agg_type = if *scalar_as_agg {
287 let mut array_args = args
290 .iter()
291 .enumerate()
292 .map(|(i, expr)| InputRef::new(i, DataType::list(expr.return_type())).into())
293 .collect_vec();
294 let schema_path = self.bind_schema_path(schema_name.as_deref());
295 let scalar_func_expr = if let Ok((func, _)) = self.catalog.get_function_by_name_inputs(
296 &self.db_name,
297 schema_path,
298 &func_name,
299 &mut array_args,
300 ) {
301 referred_udfs.insert(func.id);
303 is_udf_call = true;
304 self.check_privilege(
305 ObjectCheckItem::new(func.owner, AclMode::Execute, func.name.clone(), func.id),
306 self.database_id,
307 )?;
308
309 if !func.kind.is_scalar() {
310 return Err(ErrorCode::InvalidInputSyntax(
311 "expect a scalar function after `AGGREGATE:`".to_owned(),
312 )
313 .into());
314 }
315
316 if func.language == "sql" {
317 self.bind_sql_udf(func.clone(), array_args)?
318 } else {
319 UserDefinedFunction::new(func.clone(), array_args).into()
320 }
321 } else {
322 self.bind_builtin_scalar_function(&func_name, array_args, arg_list.variadic)?
323 };
324
325 let expr_node = match scalar_func_expr.try_to_expr_proto() {
328 Ok(expr_node) => expr_node,
329 Err(e) => {
330 return Err(ErrorCode::InvalidInputSyntax(format!(
331 "function {func_name} cannot be used after `AGGREGATE:`: {e}",
332 ))
333 .into());
334 }
335 };
336
337 Some(AggType::WrapScalar(expr_node))
339 } else {
340 None
341 };
342
343 let schema_path = self.bind_schema_path(schema_name.as_deref());
344 let udf = if wrapped_agg_type.is_none()
345 && let Ok((func, _)) = self.catalog.get_function_by_name_inputs(
346 &self.db_name,
347 schema_path,
348 &func_name,
349 &mut args,
350 ) {
351 referred_udfs.insert(func.id);
353 is_udf_call = true;
354 self.check_privilege(
355 ObjectCheckItem::new(func.owner, AclMode::Execute, func.name.clone(), func.id),
356 self.database_id,
357 )?;
358 Some(func.clone())
359 } else {
360 None
361 };
362
363 if has_secret_ref_arg && !is_udf_call {
364 return Err(ErrorCode::InvalidInputSyntax(
365 "secret reference is only allowed in user-defined function arguments".to_owned(),
366 )
367 .into());
368 }
369
370 self.included_udfs.extend(referred_udfs);
371
372 let agg_type = if wrapped_agg_type.is_some() {
373 wrapped_agg_type
374 } else if let Some(ref udf) = udf
375 && udf.kind.is_aggregate()
376 {
377 assert_ne!(udf.language, "sql", "SQL UDAF is not supported yet");
378 Some(AggType::UserDefined(udf.as_ref().into()))
379 } else {
380 AggType::from_str(&func_name).ok()
381 };
382
383 if let Some(over) = over {
385 reject_syntax!(
386 arg_list.distinct,
387 "`DISTINCT` is not allowed in window function call"
388 );
389 reject_syntax!(
390 arg_list.variadic,
391 "`VARIADIC` is not allowed in window function call"
392 );
393 reject_syntax!(
394 !arg_list.order_by.is_empty(),
395 "`ORDER BY` is not allowed in window function call argument list"
396 );
397 reject_syntax!(
398 within_group.is_some(),
399 "`WITHIN GROUP` is not allowed in window function call"
400 );
401
402 let kind = if let Some(agg_type) = agg_type {
403 WindowFuncKind::Aggregate(agg_type)
405 } else if let Ok(kind) = WindowFuncKind::from_str(&func_name) {
406 kind
407 } else {
408 bail_not_implemented!(issue = 8961, "Unrecognized window function: {}", func_name);
409 };
410 return self.bind_window_function(
411 kind,
412 args,
413 arg_list.ignore_nulls,
414 filter.as_deref(),
415 over,
416 );
417 }
418
419 reject_syntax!(
421 arg_list.ignore_nulls,
422 "`IGNORE NULLS` is not allowed in aggregate/scalar/table function call"
423 );
424
425 if let Some(agg_type) = agg_type {
427 reject_syntax!(
428 arg_list.variadic,
429 "`VARIADIC` is not allowed in aggregate function call"
430 );
431 return self.bind_aggregate_function(
432 agg_type,
433 arg_list.distinct,
434 args,
435 &arg_list.order_by,
436 within_group.as_deref(),
437 filter.as_deref(),
438 );
439 }
440
441 reject_syntax!(
443 arg_list.distinct,
444 "`DISTINCT` is not allowed in scalar/table function call"
445 );
446 reject_syntax!(
447 !arg_list.order_by.is_empty(),
448 "`ORDER BY` is not allowed in scalar/table function call"
449 );
450 reject_syntax!(
451 within_group.is_some(),
452 "`WITHIN GROUP` is not allowed in scalar/table function call"
453 );
454 reject_syntax!(
455 filter.is_some(),
456 "`FILTER` is not allowed in scalar/table function call"
457 );
458
459 {
461 if func_name.eq_ignore_ascii_case("file_scan") {
463 reject_syntax!(
464 arg_list.variadic,
465 "`VARIADIC` is not allowed in table function call"
466 );
467 self.ensure_table_function_allowed()?;
468 return Ok(TableFunction::new_file_scan(args)?.into());
469 }
470 if func_name.eq("postgres_query") {
472 reject_syntax!(
473 arg_list.variadic,
474 "`VARIADIC` is not allowed in table function call"
475 );
476 self.ensure_table_function_allowed()?;
477 let args = self
478 .bind_postgres_or_mysql_query_args(schema_name.as_deref(), args, "postgres-cdc")
479 .context("postgres_query error")?;
480 return Ok(TableFunction::new_postgres_query(args)
481 .context("postgres_query error")?
482 .into());
483 }
484 if func_name.eq("mysql_query") {
486 reject_syntax!(
487 arg_list.variadic,
488 "`VARIADIC` is not allowed in table function call"
489 );
490 self.ensure_table_function_allowed()?;
491 let args = self
492 .bind_postgres_or_mysql_query_args(schema_name.as_deref(), args, "mysql-cdc")
493 .context("mysql_query error")?;
494 return Ok(TableFunction::new_mysql_query(args)
495 .context("mysql_query error")?
496 .into());
497 }
498 if func_name.eq("internal_backfill_progress") {
500 reject_syntax!(
501 arg_list.variadic,
502 "`VARIADIC` is not allowed in table function call"
503 );
504 self.ensure_table_function_allowed()?;
505 return Ok(TableFunction::new_internal_backfill_progress().into());
506 }
507 if func_name.eq("internal_source_backfill_progress") {
509 reject_syntax!(
510 arg_list.variadic,
511 "`VARIADIC` is not allowed in table function call"
512 );
513 self.ensure_table_function_allowed()?;
514 return Ok(TableFunction::new_internal_source_backfill_progress().into());
515 }
516 if func_name.eq("internal_get_channel_delta_stats") {
518 reject_syntax!(
519 arg_list.variadic,
520 "`VARIADIC` is not allowed in table function call"
521 );
522 self.ensure_table_function_allowed()?;
523
524 return Ok(TableFunction::new_internal_get_channel_delta_stats(args).into());
525 }
526 if let Some(ref udf) = udf
528 && udf.kind.is_table()
529 {
530 reject_syntax!(
531 arg_list.variadic,
532 "`VARIADIC` is not allowed in table function call"
533 );
534 self.ensure_table_function_allowed()?;
535 if udf.language == "sql" {
536 return self.bind_sql_udf(udf.clone(), args);
537 }
538 return Ok(TableFunction::new_user_defined(udf.clone(), args).into());
539 }
540 if let Ok(function_type) = TableFunctionType::from_str(&func_name) {
542 reject_syntax!(
543 arg_list.variadic,
544 "`VARIADIC` is not allowed in table function call"
545 );
546 self.ensure_table_function_allowed()?;
547 return Ok(TableFunction::new(function_type, args)?.into());
548 }
549 }
550
551 if let Some(ref udf) = udf {
553 assert!(udf.kind.is_scalar());
554 reject_syntax!(
555 arg_list.variadic,
556 "`VARIADIC` is not allowed in user-defined function call"
557 );
558 if udf.language == "sql" {
559 return self.bind_sql_udf(udf.clone(), args);
560 }
561 return Ok(UserDefinedFunction::new(udf.clone(), args).into());
562 }
563
564 self.bind_builtin_scalar_function(&func_name, args, arg_list.variadic)
565 }
566
567 fn validate_and_bind_special_function_params(
568 &mut self,
569 func_name: &str,
570 scalar_as_agg: bool,
571 arg_list: &FunctionArgList,
572 within_group: Option<&OrderByExpr>,
573 filter: Option<&risingwave_sqlparser::ast::Expr>,
574 over: Option<&Window>,
575 ) -> Result<ExprImpl> {
576 assert!(["array_transform", "map_filter"].contains(&func_name));
577
578 reject_syntax!(
579 scalar_as_agg,
580 "`AGGREGATE:` prefix is not allowed for `{}`",
581 func_name
582 );
583 reject_syntax!(
584 !arg_list.is_args_only(),
585 "keywords like `DISTINCT`, `ORDER BY` are not allowed in `{}` argument list",
586 func_name
587 );
588 reject_syntax!(
589 within_group.is_some(),
590 "`WITHIN GROUP` is not allowed in `{}` call",
591 func_name
592 );
593 reject_syntax!(
594 filter.is_some(),
595 "`FILTER` is not allowed in `{}` call",
596 func_name
597 );
598 reject_syntax!(
599 over.is_some(),
600 "`OVER` is not allowed in `{}` call",
601 func_name
602 );
603 if func_name == "array_transform" {
604 self.bind_array_transform(&arg_list.args)
605 } else {
606 self.bind_map_filter(&arg_list.args)
607 }
608 }
609
610 fn bind_array_transform(&mut self, args: &[FunctionArg]) -> Result<ExprImpl> {
611 let [array, lambda] = args else {
612 return Err(ErrorCode::BindError(format!(
613 "`array_transform` expect two inputs `array` and `lambda`, but {} were given",
614 args.len()
615 ))
616 .into());
617 };
618
619 let bound_array = self.bind_function_arg(array)?;
620 let [bound_array] = <[ExprImpl; 1]>::try_from(bound_array).map_err(|bound_array| -> RwError {
621 ErrorCode::BindError(format!("The `array` argument for `array_transform` should be bound to one argument, but {} were got", bound_array.len()))
622 .into()
623 })?;
624
625 let inner_ty = match bound_array.return_type() {
626 DataType::List(ty) => ty.into_elem(),
627 real_type => return Err(ErrorCode::BindError(format!(
628 "The `array` argument for `array_transform` should be an array, but {} were got",
629 real_type
630 ))
631 .into()),
632 };
633
634 let ast::FunctionArgExpr::Expr(ast::Expr::LambdaFunction {
635 args: lambda_args,
636 body: lambda_body,
637 }) = lambda.get_expr()
638 else {
639 return Err(ErrorCode::BindError(
640 "The `lambda` argument for `array_transform` should be a lambda function"
641 .to_owned(),
642 )
643 .into());
644 };
645
646 let [lambda_arg] = <[Ident; 1]>::try_from(lambda_args).map_err(|args| -> RwError {
647 ErrorCode::BindError(format!(
648 "The `lambda` argument for `array_transform` should be a lambda function with one argument, but {} were given",
649 args.len()
650 ))
651 .into()
652 })?;
653
654 let bound_lambda = self.bind_unary_lambda_function(inner_ty, lambda_arg, *lambda_body)?;
655
656 let lambda_ret_type = bound_lambda.return_type();
657 let transform_ret_type = DataType::list(lambda_ret_type);
658
659 Ok(ExprImpl::FunctionCallWithLambda(Box::new(
660 FunctionCallWithLambda::new_unchecked(
661 ExprType::ArrayTransform,
662 vec![bound_array],
663 bound_lambda,
664 transform_ret_type,
665 ),
666 )))
667 }
668
669 fn bind_unary_lambda_function(
670 &mut self,
671 input_ty: DataType,
672 arg: Ident,
673 body: ast::Expr,
674 ) -> Result<ExprImpl> {
675 let lambda_args = HashMap::from([(arg.real_value(), (0usize, input_ty))]);
676 let orig_lambda_args = self.context.lambda_args.replace(lambda_args);
677 let body = self.bind_expr_inner(&body)?;
678 self.context.lambda_args = orig_lambda_args;
679
680 Ok(body)
681 }
682
683 fn bind_map_filter(&mut self, args: &[FunctionArg]) -> Result<ExprImpl> {
684 let [input, lambda] = args else {
685 return Err(ErrorCode::BindError(format!(
686 "`map_filter` requires two arguments (input_map and lambda), got {}",
687 args.len()
688 ))
689 .into());
690 };
691
692 let bound_input = self.bind_function_arg(input)?;
693 let [bound_input] = <[ExprImpl; 1]>::try_from(bound_input).map_err(|e| {
694 ErrorCode::BindError(format!(
695 "Input argument should resolve to single expression, got {}",
696 e.len()
697 ))
698 })?;
699
700 let (key_type, value_type) = match bound_input.return_type() {
701 DataType::Map(map_type) => (map_type.key().clone(), map_type.value().clone()),
702 t => {
703 return Err(
704 ErrorCode::BindError(format!("Input must be Map type, got {}", t)).into(),
705 );
706 }
707 };
708
709 let ast::FunctionArgExpr::Expr(ast::Expr::LambdaFunction {
710 args: lambda_args,
711 body: lambda_body,
712 }) = lambda.get_expr()
713 else {
714 return Err(ErrorCode::BindError(
715 "Second argument must be a lambda function".to_owned(),
716 )
717 .into());
718 };
719
720 let [key_arg, value_arg] = <[Ident; 2]>::try_from(lambda_args).map_err(|args| {
721 ErrorCode::BindError(format!(
722 "Lambda must have exactly two parameters (key, value), got {}",
723 args.len()
724 ))
725 })?;
726
727 let bound_lambda = self.bind_binary_lambda_function(
728 key_arg,
729 key_type.clone(),
730 value_arg,
731 value_type.clone(),
732 *lambda_body,
733 )?;
734
735 let lambda_ret_type = bound_lambda.return_type();
736 if lambda_ret_type != DataType::Boolean {
737 return Err(ErrorCode::BindError(format!(
738 "Lambda must return Boolean type, got {}",
739 lambda_ret_type
740 ))
741 .into());
742 }
743
744 let map_type = MapType::from_kv(key_type, value_type);
745 let return_type = DataType::Map(map_type);
746
747 Ok(ExprImpl::FunctionCallWithLambda(Box::new(
748 FunctionCallWithLambda::new_unchecked(
749 ExprType::MapFilter,
750 vec![bound_input],
751 bound_lambda,
752 return_type,
753 ),
754 )))
755 }
756
757 fn bind_binary_lambda_function(
758 &mut self,
759 first_arg: Ident,
760 first_ty: DataType,
761 second_arg: Ident,
762 second_ty: DataType,
763 body: ast::Expr,
764 ) -> Result<ExprImpl> {
765 let lambda_args = HashMap::from([
766 (first_arg.real_value(), (0usize, first_ty)),
767 (second_arg.real_value(), (1usize, second_ty)),
768 ]);
769
770 let orig_ctx = self.context.lambda_args.replace(lambda_args);
771 let bound_body = self.bind_expr_inner(&body)?;
772 self.context.lambda_args = orig_ctx;
773
774 Ok(bound_body)
775 }
776
777 fn ensure_table_function_allowed(&self) -> Result<()> {
778 if let Some(clause) = self.context.clause {
779 match clause {
780 Clause::JoinOn
781 | Clause::Where
782 | Clause::Having
783 | Clause::Filter
784 | Clause::Values
785 | Clause::Insert
786 | Clause::GeneratedColumn => {
787 return Err(ErrorCode::InvalidInputSyntax(format!(
788 "table functions are not allowed in {}",
789 clause
790 ))
791 .into());
792 }
793 Clause::GroupBy | Clause::From => {}
794 }
795 }
796 Ok(())
797 }
798
799 pub(crate) fn extract_udf_expr(ast: Vec<Statement>) -> Result<AstExpr> {
801 if ast.len() != 1 {
802 return Err(ErrorCode::InvalidInputSyntax(
803 "the query for sql udf should contain only one statement".to_owned(),
804 )
805 .into());
806 }
807
808 let Statement::Query(query) = ast.into_iter().next().unwrap() else {
810 return Err(ErrorCode::InvalidInputSyntax(
811 "invalid function definition, please recheck the syntax".to_owned(),
812 )
813 .into());
814 };
815
816 if let Some(expr) = query.as_single_select_item() {
817 Ok(expr.clone())
819 } else {
820 Ok(AstExpr::Subquery(query))
822 }
823 }
824
825 pub fn bind_sql_udf_inner(
826 &mut self,
827 body: &str,
828 arg_names: &[String],
829 args: Vec<ExprImpl>,
830 ) -> Result<ExprImpl> {
831 let ast = Parser::parse_sql(body)?;
833
834 let stashed_arguments = self.context.sql_udf_arguments.take();
838
839 let mut arguments = HashMap::new();
841 for (i, arg) in args.into_iter().enumerate() {
842 if arg_names[i].is_empty() {
843 arguments.insert(format!("${}", i + 1), arg);
845 } else {
846 arguments.insert(arg_names[i].clone(), arg);
848 }
849 }
850 self.context.sql_udf_arguments = Some(arguments);
851
852 let Ok(expr) = Self::extract_udf_expr(ast) else {
853 return Err(ErrorCode::InvalidInputSyntax(
854 "failed to parse the input query and extract the udf expression, \
855 please recheck the syntax"
856 .to_owned(),
857 )
858 .into());
859 };
860
861 let bind_result = self.bind_expr(&expr);
862 self.context.sql_udf_arguments = stashed_arguments;
864
865 bind_result
866 }
867
868 fn bind_sql_udf(
869 &mut self,
870 func: Arc<FunctionCatalog>,
871 args: Vec<ExprImpl>,
872 ) -> Result<ExprImpl> {
873 let Some(body) = &func.body else {
874 return Err(
875 ErrorCode::InvalidInputSyntax("`body` must exist for sql udf".to_owned()).into(),
876 );
877 };
878
879 self.bind_sql_udf_inner(body, &func.arg_names, args)
880 }
881
882 pub(in crate::binder) fn bind_function_expr_arg(
883 &mut self,
884 arg_expr: &FunctionArgExpr,
885 ) -> Result<Vec<ExprImpl>> {
886 match arg_expr {
887 FunctionArgExpr::Expr(expr) => Ok(vec![self.bind_expr_inner(expr)?]),
888 FunctionArgExpr::QualifiedWildcard(_, _)
889 | FunctionArgExpr::ExprQualifiedWildcard(_, _) => Err(ErrorCode::InvalidInputSyntax(
890 format!("unexpected wildcard {}", arg_expr),
891 )
892 .into()),
893 FunctionArgExpr::Wildcard(None) => Ok(vec![]),
894 FunctionArgExpr::Wildcard(Some(_)) => unreachable!(),
895 FunctionArgExpr::SecretRef(secret_ref_value) => {
896 let (schema_name, secret_name) = Binder::resolve_schema_qualified_name(
897 &self.db_name,
898 &secret_ref_value.secret_name,
899 )?;
900 let schema_path = self.bind_schema_path(schema_name.as_deref());
901 let (secret_catalog, _) =
902 self.catalog
903 .get_secret_by_name(&self.db_name, schema_path, &secret_name)?;
904
905 self.check_privilege(
906 ObjectCheckItem::new(
907 secret_catalog.owner(),
908 AclMode::Usage,
909 secret_catalog.name.clone(),
910 secret_catalog.id,
911 ),
912 self.database_id,
913 )?;
914
915 self.included_secrets.insert(secret_catalog.id);
916
917 let ref_as = match secret_ref_value.ref_as {
918 SecretRefAsType::Text => risingwave_pb::secret::secret_ref::RefAsType::Text,
919 SecretRefAsType::File => risingwave_pb::secret::secret_ref::RefAsType::File,
920 };
921
922 Ok(vec![
923 crate::expr::SecretRef {
924 secret_id: secret_catalog.id,
925 ref_as,
926 secret_name: secret_catalog.name.clone(),
927 }
928 .into(),
929 ])
930 }
931 }
932 }
933
934 pub(in crate::binder) fn bind_function_arg(
935 &mut self,
936 arg: &FunctionArg,
937 ) -> Result<Vec<ExprImpl>> {
938 match arg {
939 FunctionArg::Unnamed(expr) => self.bind_function_expr_arg(expr),
940 FunctionArg::Named { .. } => Err(ErrorCode::InvalidInputSyntax(
941 "named function arguments are not supported yet".to_owned(),
942 )
943 .into()),
944 }
945 }
946
947 fn bind_jsonb_agg_arg(&mut self, arg: &FunctionArg) -> Result<Vec<ExprImpl>> {
948 match arg {
949 FunctionArg::Unnamed(FunctionArgExpr::QualifiedWildcard(prefix, except)) => {
950 let (schema_name, table_name) =
951 Binder::resolve_schema_qualified_name(&self.db_name, prefix)?;
952 let except_indices = self.generate_except_indices(except.as_deref())?;
953 let (begin, end) = self
954 .context
955 .resolve_relation_range(&table_name, &schema_name)?;
956 let (exprs, names) = Self::iter_bound_columns(
957 self.context.columns[begin..end]
958 .iter()
959 .filter(|c| !c.is_hidden && !except_indices.contains(&c.index)),
960 );
961 self.wrap_wildcard_exprs_as_named_row(exprs, names)
962 }
963 FunctionArg::Unnamed(FunctionArgExpr::ExprQualifiedWildcard(expr, prefix)) => {
964 let (exprs, names) = self.bind_wildcard_field_column(expr, prefix)?;
965 self.wrap_wildcard_exprs_as_named_row(exprs, names)
966 }
967 _ => self.bind_function_arg(arg),
968 }
969 }
970
971 fn wrap_wildcard_exprs_as_named_row(
972 &self,
973 exprs: Vec<ExprImpl>,
974 names: Vec<Option<String>>,
975 ) -> Result<Vec<ExprImpl>> {
976 let return_type =
977 DataType::Struct(StructType::new(
978 names.into_iter().zip_eq_fast(exprs.iter()).enumerate().map(
979 |(idx, (name, expr))| {
980 (
981 name.unwrap_or_else(|| format!("f{}", idx + 1)),
982 expr.return_type(),
983 )
984 },
985 ),
986 ));
987 Ok(vec![
988 FunctionCall::new_unchecked(ExprType::Row, exprs, return_type).into(),
989 ])
990 }
991}