JingsongLi commented on code in PR #499:
URL: https://github.com/apache/paimon-rust/pull/499#discussion_r3563699800
##########
crates/integrations/datafusion/src/sql_context.rs:
##########
@@ -1430,6 +1442,165 @@ impl SQLContext {
}
}
+ async fn handle_create_function(
+ &self,
+ create_function: &CreateFunction,
+ ) -> DFResult<DataFrame> {
+ validate_persistent_create_function(create_function)?;
+ if create_function
+ .language
+ .as_ref()
+ .is_some_and(|language|
!language.value.eq_ignore_ascii_case("sql"))
+ {
+ return Err(DataFusionError::Plan(
+ "CREATE FUNCTION only supports LANGUAGE SQL".to_string(),
+ ));
+ }
+ if matches!(
+ create_function.behavior,
+ Some(FunctionBehavior::Stable | FunctionBehavior::Volatile)
+ ) {
+ return Err(DataFusionError::Plan(
+ "CREATE FUNCTION only supports deterministic SQL
functions".to_string(),
+ ));
+ }
+ let FunctionReturnType::DataType(return_type) = create_function
+ .return_type
+ .as_ref()
+ .ok_or_else(|| DataFusionError::Plan("CREATE FUNCTION requires
RETURNS".to_string()))?
+ else {
+ return Err(DataFusionError::Plan(
+ "CREATE FUNCTION SETOF return types are not
supported".to_string(),
+ ));
+ };
+ let CreateFunctionBody::Return(body) = create_function
+ .function_body
+ .as_ref()
+ .ok_or_else(|| DataFusionError::Plan("CREATE FUNCTION requires
RETURN".to_string()))?
+ else {
+ return Err(DataFusionError::Plan(
+ "CREATE FUNCTION only supports a RETURN
expression".to_string(),
+ ));
+ };
+
+ let mut parameter_names = HashSet::new();
+ let input_params = create_function
+ .args
+ .as_deref()
+ .unwrap_or_default()
+ .iter()
+ .enumerate()
+ .map(|(id, argument)| {
+ if argument.mode.is_some() || argument.default_expr.is_some() {
+ return Err(DataFusionError::Plan(
+ "CREATE FUNCTION argument modes and defaults are not
supported".to_string(),
+ ));
+ }
+ let name = argument
+ .name
+ .clone()
+ .map(normalize_create_function_argument_name)
+ .ok_or_else(|| {
+ DataFusionError::Plan(
+ "CREATE FUNCTION arguments must have
names".to_string(),
+ )
+ })?;
+ if !parameter_names.insert(name.clone()) {
+ return Err(DataFusionError::Plan(format!(
+ "duplicate function argument name '{name}'"
+ )));
+ }
+ Ok(PaimonDataField::new(
+ id as i32,
+ name,
+ sql_data_type_to_paimon_type(&argument.data_type, true)?,
+ ))
+ })
+ .collect::<DFResult<Vec<_>>>()?;
+ let return_params = vec![PaimonDataField::new(
+ 0,
+ "result".to_string(),
+ sql_data_type_to_paimon_type(return_type, true)?,
+ )];
+ let (catalog, catalog_name, identifier) =
+ self.resolve_catalog_and_function(&create_function.name)?;
+ let function = paimon::catalog::Function::new(
+ identifier,
+ Some(input_params),
+ Some(return_params),
+ true,
+ HashMap::from([(
+ "datafusion".to_string(),
+ paimon::catalog::FunctionDefinition::Sql {
+ definition: body.to_string(),
+ },
+ )]),
+ None,
+ HashMap::new(),
+ );
+ self.validate_create_function(&function, &catalog_name)
+ .await?;
+ catalog
+ .create_function(&function, create_function.if_not_exists)
+ .await
+ .map_err(to_datafusion_error)?;
+ ok_result(&self.ctx)
+ }
+
+ async fn validate_create_function(
+ &self,
+ function: &paimon::catalog::Function,
+ catalog_name: &str,
+ ) -> DFResult<()> {
+ let arguments = function
+ .input_params()
+ .unwrap_or_default()
+ .iter()
+ .map(|field| {
+ let value =
serde_json::to_value(field.data_type()).map_err(|error| {
+ DataFusionError::Plan(format!(
+ "Invalid CREATE FUNCTION argument type '{:?}':
{error}",
+ field.data_type()
+ ))
+ })?;
+ let sql_type = value.as_str().ok_or_else(|| {
Review Comment:
Fixed in b0dbc50. CREATE FUNCTION validation placeholders and REST SQL
function return casts now both reuse the recursive table::data_type_to_sql
renderer, so ARRAY/MAP/ROW types no longer depend on JSON string serialization.
Added regression tests for ARRAY input creation and ARRAY return
creation/execution. Verified 17 persistent CREATE FUNCTION tests, 15 REST SQL
function tests, fmt/diff checks, and clippy with -D warnings.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]