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::Nullary => {
310 ensure!(
311 args.is_empty(),
312 error::FunctionArityMismatchSnafu {
313 actual: args.len(),
314 expected: 0_usize,
315 }
316 );
317 Ok(vec![])
318 }
319
320 TypeSignature::Variadic(valid_types) => {
321 values_to_vectors_by_valid_types(valid_types, args, Some(&tz))
322 }
323
324 TypeSignature::Uniform(arity, valid_types) => {
325 ensure!(
326 *arity == args.len(),
327 error::FunctionArityMismatchSnafu {
328 actual: args.len(),
329 expected: *arity,
330 }
331 );
332
333 values_to_vectors_by_valid_types(valid_types, args, Some(&tz))
334 }
335
336 TypeSignature::Exact(data_types) => {
337 ensure!(
338 args.len() == data_types.len(),
339 error::FunctionArityMismatchSnafu {
340 actual: args.len(),
341 expected: data_types.len(),
342 }
343 );
344 values_to_vectors_by_exact_types(data_types, args, Some(&tz))
345 }
346
347 TypeSignature::VariadicAny => {
348 let data_types = args
349 .iter()
350 .map(|value| try_get_data_type_for_sql_value(value))
351 .collect::<Result<Vec<_>>>()?;
352
353 values_to_vectors_by_exact_types(&data_types, args, Some(&tz))
354 }
355
356 TypeSignature::Any(arity) => {
357 ensure!(
358 *arity == args.len(),
359 error::FunctionArityMismatchSnafu {
360 actual: args.len(),
361 expected: *arity,
362 }
363 );
364
365 let data_types = args
366 .iter()
367 .map(|value| try_get_data_type_for_sql_value(value))
368 .collect::<Result<Vec<_>>>()?;
369
370 values_to_vectors_by_exact_types(&data_types, args, Some(&tz))
371 }
372
373 TypeSignature::OneOf(type_sigs) => {
374 for type_sig in type_sigs {
375 if let Ok(vectors) = args_to_vector(type_sig, args, query_ctx) {
376 return Ok(vectors);
377 }
378 }
379
380 error::BuildAdminFunctionArgsSnafu {
381 msg: "function signature not match",
382 }
383 .fail()
384 }
385
386 _ => error::BuildAdminFunctionArgsSnafu {
387 msg: format!("unknown function type signature: {type_signature:?}"),
388 }
389 .fail(),
390 }
391}
392
393fn values_to_vectors_by_exact_types(
395 exact_types: &[ArrowDataType],
396 args: &[&SqlValue],
397 tz: Option<&Timezone>,
398) -> Result<Vec<VectorRef>> {
399 args.iter()
400 .zip(exact_types.iter())
401 .map(|(value, data_type)| {
402 let schema = ColumnSchema::new(
403 DUMMY_COLUMN,
404 ConcreteDataType::from_arrow_type(data_type),
405 true,
406 );
407 let value = sql_value_to_value(&schema, value, tz, None, false)
408 .context(error::SqlCommonSnafu)?;
409
410 Ok(value_to_vector(value))
411 })
412 .collect()
413}
414
415fn values_to_vectors_by_valid_types(
417 valid_types: &[ArrowDataType],
418 args: &[&SqlValue],
419 tz: Option<&Timezone>,
420) -> Result<Vec<VectorRef>> {
421 args.iter()
422 .map(|value| {
423 for data_type in valid_types {
424 let schema = ColumnSchema::new(
425 DUMMY_COLUMN,
426 ConcreteDataType::from_arrow_type(data_type),
427 true,
428 );
429 if let Ok(value) = sql_value_to_value(&schema, value, tz, None, false) {
430 return Ok(value_to_vector(value));
431 }
432 }
433
434 error::BuildAdminFunctionArgsSnafu {
435 msg: format!("failed to cast {value}"),
436 }
437 .fail()
438 })
439 .collect::<Result<Vec<_>>>()
440}
441
442fn value_to_vector(value: Value) -> VectorRef {
444 let data_type = value.data_type();
445 let mut mutable_vector = data_type.create_mutable_vector(1);
446 mutable_vector.push_value_ref(&value.as_value_ref());
447
448 mutable_vector.to_vector()
449}
450
451fn try_get_data_type_for_sql_value(value: &SqlValue) -> Result<ArrowDataType> {
453 match value {
454 SqlValue::Number(_, _) => Ok(ArrowDataType::Float64),
455 SqlValue::Null => Ok(ArrowDataType::Null),
456 SqlValue::Boolean(_) => Ok(ArrowDataType::Boolean),
457 SqlValue::HexStringLiteral(_)
458 | SqlValue::DoubleQuotedString(_)
459 | SqlValue::SingleQuotedString(_) => Ok(ArrowDataType::Utf8),
460 _ => error::BuildAdminFunctionArgsSnafu {
461 msg: format!("unsupported sql value: {value}"),
462 }
463 .fail(),
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use std::sync::Arc;
470
471 use datafusion_expr::TypeSignature;
472 use datatypes::arrow::datatypes::DataType as ArrowDataType;
473 use datatypes::value::Value;
474 use datatypes::vectors::{Int32Vector, VectorRef};
475 use session::context::QueryContext;
476 use sql::ast::Value as SqlValue;
477 use sql::dialect::GreptimeDbDialect;
478 use sql::parser::{ParseOptions, ParserContext};
479 use sql::statements::statement::Statement;
480
481 use crate::error::Error;
482 use crate::statement::admin::{admin_output_schema, args_to_vector, immediate_result};
483
484 #[test]
485 fn test_args_to_vector_arity() {
486 let query_ctx = QueryContext::arc();
487 let value = SqlValue::SingleQuotedString("explicit-id".to_string());
488 for (signature, expected) in [
489 (TypeSignature::Nullary, 0),
490 (TypeSignature::Exact(vec![]), 0),
491 (TypeSignature::Exact(vec![ArrowDataType::Utf8]), 1),
492 (TypeSignature::Exact(vec![ArrowDataType::Utf8; 2]), 2),
493 ] {
494 for actual in 0..=3 {
495 let result = args_to_vector(&signature, &vec![&value; actual], &query_ctx);
496 if actual == expected {
497 let vectors = result.unwrap();
498 assert_eq!(vectors.len(), expected);
499 for vector in vectors {
500 assert_eq!(vector.get(0), Value::from("explicit-id"));
501 }
502 } else {
503 assert!(matches!(
504 result,
505 Err(Error::FunctionArityMismatch { actual: a, expected: e })
506 if a == actual && e == expected
507 ));
508 }
509 }
510 }
511 }
512
513 #[test]
514 fn test_admin_reconcile_catalog_nullary() {
515 let Statement::Admin(statement) = ParserContext::create_with_dialect(
516 "ADMIN reconcile_catalog()",
517 &GreptimeDbDialect {},
518 ParseOptions::default(),
519 )
520 .unwrap()
521 .remove(0) else {
522 panic!("expected ADMIN statement");
523 };
524 assert!(admin_output_schema(&statement, &QueryContext::arc()).is_some());
525 }
526
527 #[test]
528 fn empty_admin_function_result_has_no_immediate_value() {
529 let result_vector: VectorRef = Arc::new(Int32Vector::from(vec![]));
530
531 assert_eq!(immediate_result(&result_vector), None);
532 }
533}