1mod event;
16mod layer;
17
18use std::sync::Arc;
19
20use common_function::function::FunctionContext;
21use common_function::function_registry::{FUNCTION_REGISTRY, get_admin_function};
22use common_function::state::FunctionState;
23use common_query::Output;
24use common_recordbatch::{RecordBatch, RecordBatches};
25use common_sql::convert::sql_value_to_value;
26use common_telemetry::tracing;
27use common_time::Timezone;
28use datafusion_expr::TypeSignature;
29use datatypes::arrow::datatypes::DataType as ArrowDataType;
30use datatypes::data_type::DataType;
31use datatypes::prelude::ConcreteDataType;
32use datatypes::schema::{ColumnSchema, Schema};
33use datatypes::value::Value;
34use datatypes::vectors::VectorRef;
35pub use layer::{
36 AdminEventRecorderHandle, AdminFunctionLayer, AdminFunctionLayerRef,
37 AdminFunctionRecordingLayer,
38};
39use session::context::QueryContextRef;
40use snafu::{OptionExt, ResultExt, ensure};
41use sql::ast::{Expr, FunctionArg, FunctionArgExpr, FunctionArguments, Value as SqlValue};
42use sql::statements::admin::Admin;
43
44use crate::error::{self, CastSnafu, ExecuteAdminFunctionSnafu, Result};
45use crate::statement::StatementExecutor;
46
47const DUMMY_COLUMN: &str = "<dummy>";
48
49#[derive(Clone)]
51pub struct AdminFunctionRequest {
52 pub statement: Admin,
54 pub query_ctx: QueryContextRef,
56}
57
58pub struct AdminFunctionResponse {
60 pub output: Output,
62 pub immediate_result: Option<Value>,
64}
65
66#[async_trait::async_trait]
68pub trait AdminFunctionService: Send + Sync {
69 async fn call(&self, request: AdminFunctionRequest) -> Result<AdminFunctionResponse>;
71}
72
73pub type AdminFunctionServiceRef = Arc<dyn AdminFunctionService>;
75
76#[derive(Clone)]
77struct CoreAdminFunctionService {
78 query_engine: query::QueryEngineRef,
79}
80
81struct ResolvedAdminFunction {
83 admin_udf: datafusion_expr::ScalarUDF,
84 fn_name: String,
85 args: Vec<VectorRef>,
86 arg_types: Vec<ArrowDataType>,
87 ret_type: ArrowDataType,
88}
89
90fn resolve_admin_function(
93 stmt: &Admin,
94 query_ctx: &QueryContextRef,
95 state: Arc<FunctionState>,
96) -> Result<ResolvedAdminFunction> {
97 let Admin::Func(func) = stmt;
98 let func_name = func.name.to_string().to_lowercase();
100 let factory = get_admin_function(&func_name)
101 .or_else(|| FUNCTION_REGISTRY.get_function(&func_name))
102 .context(error::AdminFunctionNotFoundSnafu {
103 name: func_name.clone(),
104 })?;
105
106 let func_ctx = FunctionContext {
107 query_ctx: query_ctx.clone(),
108 state,
109 };
110
111 let admin_udf = factory.provide(func_ctx);
112 admin_udf
113 .as_async()
114 .context(error::AdminFunctionNotFoundSnafu { name: func_name })?;
115
116 let fn_name = admin_udf.name().to_string();
117 let signature = admin_udf.signature();
118
119 let FunctionArguments::List(args) = &func.args else {
121 return error::BuildAdminFunctionArgsSnafu {
122 msg: format!("unsupported function args {} for {}", func.args, fn_name),
123 }
124 .fail();
125 };
126 let arg_values = args
127 .args
128 .iter()
129 .map(|arg| {
130 let FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(value))) = arg else {
131 return error::BuildAdminFunctionArgsSnafu {
132 msg: format!("unsupported function arg {arg} for {}", fn_name),
133 }
134 .fail();
135 };
136 Ok(&value.value)
137 })
138 .collect::<Result<Vec<_>>>()?;
139
140 let args = args_to_vector(&signature.type_signature, &arg_values, query_ctx)?;
141 let arg_types = args
142 .iter()
143 .map(|arg| arg.data_type().as_arrow_type())
144 .collect::<Vec<_>>();
145 let ret_type =
146 admin_udf
147 .return_type(&arg_types)
148 .map_err(|e| error::Error::BuildAdminFunctionArgs {
149 msg: format!(
150 "Failed to get return type of admin function {}: {}",
151 fn_name, e
152 ),
153 })?;
154
155 Ok(ResolvedAdminFunction {
156 admin_udf,
157 fn_name,
158 args,
159 arg_types,
160 ret_type,
161 })
162}
163
164pub fn admin_output_schema(stmt: &Admin, query_ctx: &QueryContextRef) -> Option<Schema> {
168 let resolved =
169 resolve_admin_function(stmt, query_ctx, Arc::new(FunctionState::default())).ok()?;
170 Some(Schema::new(vec![ColumnSchema::new(
171 stmt.to_string(),
173 ConcreteDataType::from_arrow_type(&resolved.ret_type),
174 false,
175 )]))
176}
177
178impl CoreAdminFunctionService {
179 fn new(query_engine: query::QueryEngineRef) -> Self {
180 Self { query_engine }
181 }
182
183 async fn execute(&self, request: AdminFunctionRequest) -> Result<AdminFunctionResponse> {
184 let AdminFunctionRequest {
185 statement: stmt,
186 query_ctx,
187 } = request;
188
189 let resolved = resolve_admin_function(
190 &stmt,
191 &query_ctx,
192 self.query_engine.engine_state().function_state(),
193 )?;
194 let ResolvedAdminFunction {
195 admin_udf,
196 fn_name,
197 args,
198 arg_types,
199 ret_type,
200 } = resolved;
201 let admin_async_fn = admin_udf
202 .as_async()
203 .context(error::AdminFunctionNotFoundSnafu {
204 name: fn_name.clone(),
205 })?;
206
207 let columnar_args: Vec<datafusion_expr::ColumnarValue> = args
209 .iter()
210 .map(|vector| datafusion_expr::ColumnarValue::Array(vector.to_arrow_array()))
211 .collect();
212
213 let func_args = datafusion::logical_expr::ScalarFunctionArgs {
215 args: columnar_args,
216 arg_fields: args
217 .iter()
218 .enumerate()
219 .map(|(i, vector)| {
220 Arc::new(arrow::datatypes::Field::new(
221 format!("arg_{}", i),
222 arg_types[i].clone(),
223 vector.null_count() > 0,
224 ))
225 })
226 .collect(),
227 return_field: Arc::new(arrow::datatypes::Field::new("result", ret_type, true)),
228 number_rows: if args.is_empty() { 1 } else { args[0].len() },
229 config_options: Arc::new(query_ctx.create_config_options()),
230 };
231
232 let result_columnar = admin_async_fn
234 .invoke_async_with_args(func_args)
235 .await
236 .with_context(|_| ExecuteAdminFunctionSnafu { msg: fn_name })?;
237
238 let result_columnar: common_query::prelude::ColumnarValue =
240 (&result_columnar).try_into().context(CastSnafu)?;
241
242 let result_vector: VectorRef = result_columnar.try_into_vector(1).context(CastSnafu)?;
243 let immediate_result = immediate_result(&result_vector);
244
245 let column_schemas = vec![ColumnSchema::new(
246 stmt.to_string(),
248 result_vector.data_type(),
249 false,
250 )];
251 let schema = Arc::new(Schema::new(column_schemas));
252 let batch = RecordBatch::new(schema.clone(), vec![result_vector])
253 .context(error::BuildRecordBatchSnafu)?;
254 let batches =
255 RecordBatches::try_new(schema, vec![batch]).context(error::BuildRecordBatchSnafu)?;
256
257 Ok(AdminFunctionResponse {
258 output: Output::new_with_record_batches(batches),
259 immediate_result,
260 })
261 }
262}
263
264fn immediate_result(result_vector: &VectorRef) -> Option<Value> {
265 (!result_vector.is_empty()).then(|| result_vector.get(0))
266}
267
268#[async_trait::async_trait]
269impl AdminFunctionService for CoreAdminFunctionService {
270 async fn call(&self, request: AdminFunctionRequest) -> Result<AdminFunctionResponse> {
271 self.execute(request).await
272 }
273}
274
275pub(crate) fn new_admin_function_service(
277 query_engine: query::QueryEngineRef,
278) -> AdminFunctionServiceRef {
279 Arc::new(CoreAdminFunctionService::new(query_engine))
280}
281
282impl StatementExecutor {
283 #[tracing::instrument(skip_all)]
285 pub(crate) async fn execute_admin_command(
286 &self,
287 stmt: Admin,
288 query_ctx: QueryContextRef,
289 ) -> Result<Output> {
290 self.admin_function_service
291 .call(AdminFunctionRequest {
292 statement: stmt,
293 query_ctx,
294 })
295 .await
296 .map(|response| response.output)
297 }
298}
299
300fn args_to_vector(
302 type_signature: &TypeSignature,
303 args: &Vec<&SqlValue>,
304 query_ctx: &QueryContextRef,
305) -> Result<Vec<VectorRef>> {
306 let tz = query_ctx.timezone();
307
308 match type_signature {
309 TypeSignature::Variadic(valid_types) => {
310 values_to_vectors_by_valid_types(valid_types, args, Some(&tz))
311 }
312
313 TypeSignature::Uniform(arity, valid_types) => {
314 ensure!(
315 *arity == args.len(),
316 error::FunctionArityMismatchSnafu {
317 actual: args.len(),
318 expected: *arity,
319 }
320 );
321
322 values_to_vectors_by_valid_types(valid_types, args, Some(&tz))
323 }
324
325 TypeSignature::Exact(data_types) => {
326 values_to_vectors_by_exact_types(data_types, args, Some(&tz))
327 }
328
329 TypeSignature::VariadicAny => {
330 let data_types = args
331 .iter()
332 .map(|value| try_get_data_type_for_sql_value(value))
333 .collect::<Result<Vec<_>>>()?;
334
335 values_to_vectors_by_exact_types(&data_types, args, Some(&tz))
336 }
337
338 TypeSignature::Any(arity) => {
339 ensure!(
340 *arity == args.len(),
341 error::FunctionArityMismatchSnafu {
342 actual: args.len(),
343 expected: *arity,
344 }
345 );
346
347 let data_types = args
348 .iter()
349 .map(|value| try_get_data_type_for_sql_value(value))
350 .collect::<Result<Vec<_>>>()?;
351
352 values_to_vectors_by_exact_types(&data_types, args, Some(&tz))
353 }
354
355 TypeSignature::OneOf(type_sigs) => {
356 for type_sig in type_sigs {
357 if let Ok(vectors) = args_to_vector(type_sig, args, query_ctx) {
358 return Ok(vectors);
359 }
360 }
361
362 error::BuildAdminFunctionArgsSnafu {
363 msg: "function signature not match",
364 }
365 .fail()
366 }
367
368 _ => error::BuildAdminFunctionArgsSnafu {
369 msg: format!("unknown function type signature: {type_signature:?}"),
370 }
371 .fail(),
372 }
373}
374
375fn values_to_vectors_by_exact_types(
377 exact_types: &[ArrowDataType],
378 args: &[&SqlValue],
379 tz: Option<&Timezone>,
380) -> Result<Vec<VectorRef>> {
381 args.iter()
382 .zip(exact_types.iter())
383 .map(|(value, data_type)| {
384 let schema = ColumnSchema::new(
385 DUMMY_COLUMN,
386 ConcreteDataType::from_arrow_type(data_type),
387 true,
388 );
389 let value = sql_value_to_value(&schema, value, tz, None, false)
390 .context(error::SqlCommonSnafu)?;
391
392 Ok(value_to_vector(value))
393 })
394 .collect()
395}
396
397fn values_to_vectors_by_valid_types(
399 valid_types: &[ArrowDataType],
400 args: &[&SqlValue],
401 tz: Option<&Timezone>,
402) -> Result<Vec<VectorRef>> {
403 args.iter()
404 .map(|value| {
405 for data_type in valid_types {
406 let schema = ColumnSchema::new(
407 DUMMY_COLUMN,
408 ConcreteDataType::from_arrow_type(data_type),
409 true,
410 );
411 if let Ok(value) = sql_value_to_value(&schema, value, tz, None, false) {
412 return Ok(value_to_vector(value));
413 }
414 }
415
416 error::BuildAdminFunctionArgsSnafu {
417 msg: format!("failed to cast {value}"),
418 }
419 .fail()
420 })
421 .collect::<Result<Vec<_>>>()
422}
423
424fn value_to_vector(value: Value) -> VectorRef {
426 let data_type = value.data_type();
427 let mut mutable_vector = data_type.create_mutable_vector(1);
428 mutable_vector.push_value_ref(&value.as_value_ref());
429
430 mutable_vector.to_vector()
431}
432
433fn try_get_data_type_for_sql_value(value: &SqlValue) -> Result<ArrowDataType> {
435 match value {
436 SqlValue::Number(_, _) => Ok(ArrowDataType::Float64),
437 SqlValue::Null => Ok(ArrowDataType::Null),
438 SqlValue::Boolean(_) => Ok(ArrowDataType::Boolean),
439 SqlValue::HexStringLiteral(_)
440 | SqlValue::DoubleQuotedString(_)
441 | SqlValue::SingleQuotedString(_) => Ok(ArrowDataType::Utf8),
442 _ => error::BuildAdminFunctionArgsSnafu {
443 msg: format!("unsupported sql value: {value}"),
444 }
445 .fail(),
446 }
447}
448
449#[cfg(test)]
450mod tests {
451 use std::sync::Arc;
452
453 use datatypes::vectors::{Int32Vector, VectorRef};
454
455 use crate::statement::admin::immediate_result;
456
457 #[test]
458 fn empty_admin_function_result_has_no_immediate_value() {
459 let result_vector: VectorRef = Arc::new(Int32Vector::from(vec![]));
460
461 assert_eq!(immediate_result(&result_vector), None);
462 }
463}