1use std::fmt;
28use std::sync::Arc;
29
30use datafusion_common::tree_node::TreeNodeRecursion;
31use datafusion_common::{Result, ScalarValue, Statistics, exec_err, internal_err};
32use datafusion_execution::TaskContext;
33use datafusion_expr::physical_planning_context::{ScalarSubqueryResults, SubqueryIndex};
34use datafusion_physical_expr::PhysicalExpr;
35
36use crate::execution_plan::{CardinalityEffect, ExecutionPlan, PlanProperties};
37use crate::joins::utils::{OnceAsync, OnceFut};
38use crate::statistics::{ChildStats, StatisticsArgs};
39use crate::stream::RecordBatchStreamAdapter;
40use crate::{
41 ChildrenPropertiesMode, DisplayAs, DisplayFormatType, ReplaceChildrenOptions,
42 SendableRecordBatchStream,
43};
44
45use futures::StreamExt;
46use futures::TryStreamExt;
47
48#[derive(Debug, Clone)]
55pub struct ScalarSubqueryLink {
56 pub plan: Arc<dyn ExecutionPlan>,
58 pub index: SubqueryIndex,
60}
61
62#[derive(Debug)]
85pub struct ScalarSubqueryExec {
86 input: Arc<dyn ExecutionPlan>,
88 subqueries: Vec<ScalarSubqueryLink>,
90 subquery_future: Arc<OnceAsync<()>>,
92 results: ScalarSubqueryResults,
95 cache: Arc<PlanProperties>,
97}
98
99impl ScalarSubqueryExec {
100 pub fn new(
101 input: Arc<dyn ExecutionPlan>,
102 subqueries: Vec<ScalarSubqueryLink>,
103 results: ScalarSubqueryResults,
104 ) -> Self {
105 let cache = Arc::clone(input.properties());
106 Self {
107 input,
108 subqueries,
109 subquery_future: Arc::default(),
110 results,
111 cache,
112 }
113 }
114
115 pub fn input(&self) -> &Arc<dyn ExecutionPlan> {
116 &self.input
117 }
118
119 pub fn subqueries(&self) -> &[ScalarSubqueryLink] {
120 &self.subqueries
121 }
122
123 pub fn results(&self) -> &ScalarSubqueryResults {
124 &self.results
125 }
126
127 fn true_for_input_only(&self) -> Vec<bool> {
130 std::iter::once(true)
131 .chain(std::iter::repeat_n(false, self.subqueries.len()))
132 .collect()
133 }
134}
135
136impl DisplayAs for ScalarSubqueryExec {
137 fn fmt_as(&self, t: DisplayFormatType, f: &mut fmt::Formatter) -> fmt::Result {
138 match t {
139 DisplayFormatType::Default | DisplayFormatType::Verbose => {
140 write!(
141 f,
142 "ScalarSubqueryExec: subqueries={}",
143 self.subqueries.len()
144 )
145 }
146 DisplayFormatType::TreeRender => {
147 write!(f, "")
148 }
149 }
150 }
151}
152
153impl ExecutionPlan for ScalarSubqueryExec {
154 fn name(&self) -> &'static str {
155 "ScalarSubqueryExec"
156 }
157
158 fn properties(&self) -> &Arc<PlanProperties> {
159 &self.cache
160 }
161
162 fn children(&self) -> Vec<&Arc<dyn ExecutionPlan>> {
163 let mut children = vec![&self.input];
164 for sq in &self.subqueries {
165 children.push(&sq.plan);
166 }
167 children
168 }
169
170 fn replace_children(
171 self: Arc<Self>,
172 mut children: Vec<Arc<dyn ExecutionPlan>>,
173 _: ReplaceChildrenOptions,
174 ) -> Result<Arc<dyn ExecutionPlan>> {
175 let input = children.remove(0);
177 let subqueries = self
178 .subqueries
179 .iter()
180 .zip(children)
181 .map(|(sq, new_plan)| ScalarSubqueryLink {
182 plan: new_plan,
183 index: sq.index,
184 })
185 .collect();
186 Ok(Arc::new(ScalarSubqueryExec::new(
187 input,
188 subqueries,
189 self.results.clone(),
190 )))
191 }
192
193 fn with_new_children(
194 self: Arc<Self>,
195 children: Vec<Arc<dyn ExecutionPlan>>,
196 ) -> Result<Arc<dyn ExecutionPlan>> {
197 self.replace_children(
198 children,
199 ReplaceChildrenOptions::new(ChildrenPropertiesMode::Recompute),
200 )
201 }
202
203 fn reset_state(self: Arc<Self>) -> Result<Arc<dyn ExecutionPlan>> {
204 self.results.clear();
205 Ok(Arc::new(ScalarSubqueryExec {
206 input: Arc::clone(&self.input),
207 subqueries: self.subqueries.clone(),
208 subquery_future: Arc::default(),
209 results: self.results.clone(),
210 cache: Arc::clone(&self.cache),
211 }))
212 }
213
214 fn execute(
215 &self,
216 partition: usize,
217 context: Arc<TaskContext>,
218 ) -> Result<SendableRecordBatchStream> {
219 let subqueries = self.subqueries.clone();
220 let results = self.results.clone();
221 let planning_ctx = Arc::clone(&context);
222 let mut subquery_future = self.subquery_future.try_once(move || {
223 Ok(async move { execute_subqueries(subqueries, results, planning_ctx).await })
224 })?;
225 let input = Arc::clone(&self.input);
226 let schema = self.schema();
227
228 Ok(Box::pin(RecordBatchStreamAdapter::new(
229 schema,
230 futures::stream::once(async move {
231 wait_for_subqueries(&mut subquery_future).await?;
234
235 input.execute(partition, context)
238 })
239 .try_flatten(),
240 )))
241 }
242
243 fn apply_expressions(
244 &self,
245 _f: &mut dyn FnMut(&Arc<dyn PhysicalExpr>) -> Result<TreeNodeRecursion>,
246 ) -> Result<TreeNodeRecursion> {
247 Ok(TreeNodeRecursion::Continue)
248 }
249
250 fn maintains_input_order(&self) -> Vec<bool> {
251 self.true_for_input_only()
254 }
255
256 fn benefits_from_input_partitioning(&self) -> Vec<bool> {
257 vec![false; self.subqueries.len() + 1]
260 }
261
262 fn child_stats_requests(&self, partition: Option<usize>) -> Vec<ChildStats> {
263 let mut requests = vec![ChildStats::Skip; 1 + self.subqueries.len()];
265 requests[0] = ChildStats::At(partition);
266 requests
267 }
268
269 fn statistics_from_inputs(
270 &self,
271 input_stats: &[Arc<Statistics>],
272 _args: &StatisticsArgs,
273 ) -> Result<Arc<Statistics>> {
274 Ok(Arc::clone(&input_stats[0]))
275 }
276
277 fn cardinality_effect(&self) -> CardinalityEffect {
278 CardinalityEffect::Equal
279 }
280
281 #[cfg(feature = "proto")]
282 fn try_to_proto(
283 &self,
284 ctx: &crate::proto::ExecutionPlanEncodeCtx<'_>,
285 ) -> Result<Option<datafusion_proto_models::protobuf::PhysicalPlanNode>> {
286 use datafusion_proto_models::protobuf;
287
288 let input = ctx.encode_child(self.input())?;
289 let subqueries =
291 ctx.encode_children(self.subqueries().iter().map(|subquery| &subquery.plan))?;
292 Ok(Some(protobuf::PhysicalPlanNode {
293 physical_plan_type: Some(
294 protobuf::physical_plan_node::PhysicalPlanType::ScalarSubquery(Box::new(
295 protobuf::ScalarSubqueryExecNode {
296 input: Some(Box::new(input)),
297 subqueries,
298 },
299 )),
300 ),
301 }))
302 }
303}
304
305#[cfg(feature = "proto")]
306impl ScalarSubqueryExec {
307 pub fn try_from_proto(
309 node: &datafusion_proto_models::protobuf::PhysicalPlanNode,
310 ctx: &crate::proto::ExecutionPlanDecodeCtx<'_>,
311 ) -> Result<Arc<dyn ExecutionPlan>> {
312 use datafusion_proto_models::protobuf;
313
314 let scalar_subquery = crate::expect_plan_variant!(
315 node,
316 protobuf::physical_plan_node::PhysicalPlanType::ScalarSubquery,
317 "ScalarSubqueryExec",
318 );
319 let results = ScalarSubqueryResults::new(scalar_subquery.subqueries.len());
320 let input_node = scalar_subquery.input.as_deref().ok_or_else(|| {
321 datafusion_common::internal_datafusion_err!(
322 "ScalarSubqueryExec is missing required field 'input'"
323 )
324 })?;
325 let input =
327 ctx.decode_child_with_scalar_subquery_results(input_node, results.clone())?;
328 let subqueries = scalar_subquery
329 .subqueries
330 .iter()
331 .enumerate()
332 .map(|(index, plan)| {
333 Ok(ScalarSubqueryLink {
334 plan: ctx.decode_child(plan)?,
335 index: SubqueryIndex::new(index),
336 })
337 })
338 .collect::<Result<Vec<_>>>()?;
339
340 Ok(Arc::new(Self::new(input, subqueries, results)))
341 }
342}
343
344async fn wait_for_subqueries(fut: &mut OnceFut<()>) -> Result<()> {
346 std::future::poll_fn(|cx| fut.get_shared(cx)).await?;
347 Ok(())
348}
349
350async fn execute_subqueries(
351 subqueries: Vec<ScalarSubqueryLink>,
352 results: ScalarSubqueryResults,
353 context: Arc<TaskContext>,
354) -> Result<()> {
355 let futures = subqueries.iter().map(|sq| {
358 let plan = Arc::clone(&sq.plan);
359 let ctx = Arc::clone(&context);
360 let results = results.clone();
361 let index = sq.index;
362 async move {
363 let value = execute_scalar_subquery(plan, ctx).await?;
364 results.set(index, value)?;
365 Ok(()) as Result<()>
366 }
367 });
368 futures::future::try_join_all(futures).await?;
369 Ok(())
370}
371
372async fn execute_scalar_subquery(
376 plan: Arc<dyn ExecutionPlan>,
377 context: Arc<TaskContext>,
378) -> Result<ScalarValue> {
379 let schema = plan.schema();
380 if schema.fields().len() != 1 {
381 return internal_err!(
383 "Scalar subquery must return exactly one column, got {}",
384 schema.fields().len()
385 );
386 }
387
388 let mut stream = crate::execute_stream(plan, context)?;
389 let mut result: Option<ScalarValue> = None;
390
391 while let Some(batch) = stream.next().await.transpose()? {
392 if batch.num_rows() == 0 {
393 continue;
394 }
395 if result.is_some() || batch.num_rows() > 1 {
396 return exec_err!("Scalar subquery returned more than one row");
397 }
398 result = Some(ScalarValue::try_from_array(batch.column(0), 0)?);
399 }
400
401 match result {
403 Some(v) => Ok(v),
404 None => ScalarValue::try_from(schema.field(0).data_type()),
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411 use crate::test::{self, TestMemoryExec};
412 use crate::{
413 execution_plan::reset_plan_states,
414 projection::{ProjectionExec, ProjectionExpr},
415 };
416
417 use std::sync::atomic::{AtomicUsize, Ordering};
418
419 use crate::test::exec::ErrorExec;
420 use arrow::array::{Int32Array, Int64Array};
421 use arrow::datatypes::{DataType, Field, Schema};
422 use arrow::record_batch::RecordBatch;
423 use datafusion_physical_expr::scalar_subquery::ScalarSubqueryExpr;
424
425 enum ExpectedSubqueryResult {
426 Value(ScalarValue),
427 Error(&'static str),
428 }
429
430 #[derive(Debug)]
431 struct CountingExec {
432 inner: Arc<dyn ExecutionPlan>,
433 execute_calls: Arc<AtomicUsize>,
434 }
435
436 impl CountingExec {
437 fn new(inner: Arc<dyn ExecutionPlan>, execute_calls: Arc<AtomicUsize>) -> Self {
438 Self {
439 inner,
440 execute_calls,
441 }
442 }
443 }
444
445 impl DisplayAs for CountingExec {
446 fn fmt_as(&self, t: DisplayFormatType, f: &mut fmt::Formatter) -> fmt::Result {
447 match t {
448 DisplayFormatType::Default | DisplayFormatType::Verbose => {
449 write!(f, "CountingExec")
450 }
451 DisplayFormatType::TreeRender => write!(f, ""),
452 }
453 }
454 }
455
456 impl ExecutionPlan for CountingExec {
457 fn name(&self) -> &'static str {
458 "CountingExec"
459 }
460
461 fn properties(&self) -> &Arc<PlanProperties> {
462 self.inner.properties()
463 }
464
465 fn children(&self) -> Vec<&Arc<dyn ExecutionPlan>> {
466 vec![&self.inner]
467 }
468
469 fn replace_children(
470 self: Arc<Self>,
471 mut children: Vec<Arc<dyn ExecutionPlan>>,
472 _: ReplaceChildrenOptions,
473 ) -> Result<Arc<dyn ExecutionPlan>> {
474 Ok(Arc::new(Self::new(
475 children.remove(0),
476 Arc::clone(&self.execute_calls),
477 )))
478 }
479
480 fn apply_expressions(
481 &self,
482 _f: &mut dyn FnMut(&Arc<dyn PhysicalExpr>) -> Result<TreeNodeRecursion>,
483 ) -> Result<TreeNodeRecursion> {
484 Ok(TreeNodeRecursion::Continue)
485 }
486
487 fn with_new_children(
488 self: Arc<Self>,
489 children: Vec<Arc<dyn ExecutionPlan>>,
490 ) -> Result<Arc<dyn ExecutionPlan>> {
491 self.replace_children(
492 children,
493 ReplaceChildrenOptions::new(ChildrenPropertiesMode::Recompute),
494 )
495 }
496
497 fn execute(
498 &self,
499 partition: usize,
500 context: Arc<TaskContext>,
501 ) -> Result<SendableRecordBatchStream> {
502 self.execute_calls.fetch_add(1, Ordering::SeqCst);
503 self.inner.execute(partition, context)
504 }
505 }
506
507 fn make_subquery_plan(batches: Vec<RecordBatch>) -> Arc<dyn ExecutionPlan> {
508 let schema = batches[0].schema();
509 TestMemoryExec::try_new_exec(&[batches], schema, None).unwrap()
510 }
511
512 fn int32_batch(values: Vec<i32>) -> RecordBatch {
513 let schema = Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)]));
514 RecordBatch::try_new(schema, vec![Arc::new(Int32Array::from(values))]).unwrap()
515 }
516
517 fn empty_int64_batch() -> RecordBatch {
518 let schema = Arc::new(Schema::new(vec![Field::new("a", DataType::Int64, true)]));
519 RecordBatch::try_new(schema, vec![Arc::new(Int64Array::from(vec![] as Vec<i64>))])
520 .unwrap()
521 }
522
523 fn placeholder_input() -> Arc<dyn ExecutionPlan> {
524 Arc::new(crate::placeholder_row::PlaceholderRowExec::new(
525 test::aggr_test_schema(),
526 ))
527 }
528
529 fn single_subquery_exec(
530 input: Arc<dyn ExecutionPlan>,
531 subquery_plan: Arc<dyn ExecutionPlan>,
532 results: ScalarSubqueryResults,
533 ) -> ScalarSubqueryExec {
534 ScalarSubqueryExec::new(
535 input,
536 vec![ScalarSubqueryLink {
537 plan: subquery_plan,
538 index: SubqueryIndex::new(0),
539 }],
540 results,
541 )
542 }
543
544 fn scalar_subquery_projection_input(
545 results: ScalarSubqueryResults,
546 ) -> Result<Arc<dyn ExecutionPlan>> {
547 Ok(Arc::new(ProjectionExec::try_new(
548 vec![ProjectionExpr {
549 expr: Arc::new(ScalarSubqueryExpr::new(
550 DataType::Int32,
551 false,
552 SubqueryIndex::new(0),
553 results,
554 )),
555 alias: "sq".to_string(),
556 }],
557 placeholder_input(),
558 )?))
559 }
560
561 fn extract_single_int32_value(batches: &[RecordBatch]) -> i32 {
562 assert_eq!(batches.len(), 1);
563 let values = batches[0]
564 .column(0)
565 .as_any()
566 .downcast_ref::<Int32Array>()
567 .unwrap();
568 assert_eq!(values.len(), 1);
569 values.value(0)
570 }
571
572 #[tokio::test]
573 async fn test_execute_scalar_subquery_row_count_semantics() -> Result<()> {
574 for (name, plan, expected) in [
575 (
576 "single_row",
577 make_subquery_plan(vec![int32_batch(vec![42])]),
578 ExpectedSubqueryResult::Value(ScalarValue::Int32(Some(42))),
579 ),
580 (
581 "zero_rows",
582 make_subquery_plan(vec![empty_int64_batch()]),
583 ExpectedSubqueryResult::Value(ScalarValue::Int64(None)),
584 ),
585 (
586 "multiple_rows",
587 make_subquery_plan(vec![int32_batch(vec![1, 2, 3])]),
588 ExpectedSubqueryResult::Error("more than one row"),
589 ),
590 ] {
591 let actual =
592 execute_scalar_subquery(plan, Arc::new(TaskContext::default())).await;
593 match expected {
594 ExpectedSubqueryResult::Value(expected) => {
595 assert_eq!(actual?, expected, "{name}");
596 }
597 ExpectedSubqueryResult::Error(expected) => {
598 let err = actual.expect_err(name);
599 assert!(
600 err.to_string().contains(expected),
601 "{name}: expected error containing '{expected}', got {err}"
602 );
603 }
604 }
605 }
606
607 Ok(())
608 }
609
610 #[tokio::test]
611 async fn test_failed_subquery_is_not_retried() -> Result<()> {
612 let execute_calls = Arc::new(AtomicUsize::new(0));
613 let subquery_plan = Arc::new(CountingExec::new(
614 Arc::new(ErrorExec::new()),
615 Arc::clone(&execute_calls),
616 ));
617 let exec = single_subquery_exec(
618 placeholder_input(),
619 subquery_plan,
620 ScalarSubqueryResults::new(1),
621 );
622
623 let ctx = Arc::new(TaskContext::default());
624 let stream = exec.execute(0, Arc::clone(&ctx))?;
625 assert!(crate::common::collect(stream).await.is_err());
626
627 let stream = exec.execute(0, ctx)?;
628 assert!(crate::common::collect(stream).await.is_err());
629
630 assert_eq!(execute_calls.load(Ordering::SeqCst), 1);
631 Ok(())
632 }
633
634 #[tokio::test]
635 async fn test_reset_state_clears_results_and_reexecutes_subqueries() -> Result<()> {
636 let execute_calls = Arc::new(AtomicUsize::new(0));
637 let results = ScalarSubqueryResults::new(1);
638 let subquery_plan = Arc::new(CountingExec::new(
639 make_subquery_plan(vec![int32_batch(vec![42])]),
640 Arc::clone(&execute_calls),
641 ));
642 let exec: Arc<dyn ExecutionPlan> = Arc::new(single_subquery_exec(
643 scalar_subquery_projection_input(results.clone())?,
644 subquery_plan,
645 results.clone(),
646 ));
647
648 let batches =
649 crate::common::collect(exec.execute(0, Arc::new(TaskContext::default()))?)
650 .await?;
651 assert_eq!(extract_single_int32_value(&batches), 42);
652 assert_eq!(
653 results.get(SubqueryIndex::new(0)),
654 Some(ScalarValue::Int32(Some(42)))
655 );
656
657 let reset_exec = reset_plan_states(Arc::clone(&exec))?;
658 assert_eq!(results.get(SubqueryIndex::new(0)), None);
659
660 let reset_batches = crate::common::collect(
661 reset_exec.execute(0, Arc::new(TaskContext::default()))?,
662 )
663 .await?;
664 assert_eq!(extract_single_int32_value(&reset_batches), 42);
665 assert_eq!(
666 results.get(SubqueryIndex::new(0)),
667 Some(ScalarValue::Int32(Some(42)))
668 );
669 assert_eq!(execute_calls.load(Ordering::SeqCst), 2);
670
671 Ok(())
672 }
673}