Skip to main content

query/dist_plan/
dyn_filter_bridge.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::sync::Arc;
17
18use common_query::request::{
19    DynFilterPayload, INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY, InitialDynFilterReg,
20    InitialDynFilterRegs, InitialDynFilterSnapshot, REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
21};
22use datafusion_common::Result;
23use datafusion_physical_expr::PhysicalExpr;
24use datafusion_physical_expr::expressions::DynamicFilterPhysicalExpr;
25use session::context::{QueryContext, QueryContextRef};
26use store_api::storage::RegionId;
27
28use crate::dist_plan::filter_id::build_remote_dyn_filter_id;
29use crate::dist_plan::{FilterId, QueryDynFilterRegistry, RemoteDynFilterProducerId, Subscriber};
30
31#[derive(Debug, Clone)]
32pub(crate) struct CapturedDynFilter {
33    filter_id: FilterId,
34    initial_registration: InitialDynFilterReg,
35    pub(crate) alive_dyn_filter: Arc<DynamicFilterPhysicalExpr>,
36}
37
38#[derive(Debug, Clone)]
39pub(crate) struct RemoteDynFilterPushdown {
40    pub(crate) captured_dyn_filters: Vec<CapturedDynFilter>,
41    /// Preflight result per parent filter.
42    pub(crate) pushed_down: Vec<bool>,
43}
44
45pub(crate) fn capture_remote_dyn_filters_for_pushdown(
46    remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
47    parent_filters: Vec<Arc<dyn datafusion::physical_plan::PhysicalExpr>>,
48) -> RemoteDynFilterPushdown {
49    let mut pushed_down = Vec::with_capacity(parent_filters.len());
50    let mut captured_dyn_filters = Vec::new();
51
52    for (producer_local_ordinal, filter) in parent_filters.into_iter().enumerate() {
53        let Some(alive_dyn_filter) = downcast_dynamic_filter(filter) else {
54            pushed_down.push(false);
55            continue;
56        };
57
58        match build_captured_dyn_filter(
59            remote_dyn_filter_producer_id,
60            producer_local_ordinal,
61            alive_dyn_filter,
62        ) {
63            Ok(captured_dyn_filter) => {
64                pushed_down.push(true);
65                captured_dyn_filters.push(captured_dyn_filter);
66            }
67            Err(error) => {
68                common_telemetry::warn!(error; "Remote dyn filter is not pushed down because initial registration cannot be built");
69                pushed_down.push(false);
70            }
71        }
72    }
73
74    if let Err(error) = validate_initial_registrations_for_pushdown(&captured_dyn_filters) {
75        common_telemetry::warn!(error; "Remote dyn filters are not pushed down because initial registrations are invalid");
76        return RemoteDynFilterPushdown {
77            captured_dyn_filters: Vec::new(),
78            pushed_down: vec![false; pushed_down.len()],
79        };
80    }
81
82    RemoteDynFilterPushdown {
83        captured_dyn_filters,
84        pushed_down,
85    }
86}
87
88fn downcast_dynamic_filter(
89    expr: Arc<dyn datafusion::physical_plan::PhysicalExpr>,
90) -> Option<Arc<DynamicFilterPhysicalExpr>> {
91    (expr as Arc<dyn Any + Send + Sync + 'static>)
92        .downcast::<DynamicFilterPhysicalExpr>()
93        .ok()
94}
95
96pub(crate) fn register_dyn_filters_for_region(
97    registry: &QueryDynFilterRegistry,
98    region_id: RegionId,
99    captured_dyn_filters: &[CapturedDynFilter],
100) {
101    for captured_dyn_filter in captured_dyn_filters {
102        let _ = registry.register_remote_dyn_filter(
103            captured_dyn_filter.filter_id.clone(),
104            captured_dyn_filter.alive_dyn_filter.clone(),
105        );
106        let _ = registry
107            .register_subscriber(&captured_dyn_filter.filter_id, Subscriber::new(region_id));
108    }
109}
110
111fn build_captured_dyn_filter(
112    remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
113    producer_local_ordinal: usize,
114    alive_dyn_filter: Arc<DynamicFilterPhysicalExpr>,
115) -> Result<CapturedDynFilter> {
116    let children = alive_dyn_filter
117        .children()
118        .into_iter()
119        .cloned()
120        .collect::<Vec<_>>();
121    let filter_id = build_remote_dyn_filter_id(
122        remote_dyn_filter_producer_id,
123        producer_local_ordinal,
124        &children,
125    )?;
126    let initial_registration =
127        InitialDynFilterReg::from_filter_id_and_children(filter_id.to_string(), &children)?;
128
129    Ok(CapturedDynFilter {
130        filter_id,
131        initial_registration: attach_initial_snapshot(initial_registration, &alive_dyn_filter),
132        alive_dyn_filter,
133    })
134}
135
136fn validate_initial_registrations_for_pushdown(
137    captured_dyn_filters: &[CapturedDynFilter],
138) -> std::result::Result<(), String> {
139    let regs = build_initial_dyn_filter_regs_for_region(captured_dyn_filters);
140    regs.validate_default_bounds()?;
141    regs.to_extension_value()
142        .map_err(|error| error.to_string())?;
143    Ok(())
144}
145
146fn attach_initial_snapshot(
147    initial_registration: InitialDynFilterReg,
148    alive_dyn_filter: &DynamicFilterPhysicalExpr,
149) -> InitialDynFilterReg {
150    let Some(initial_snapshot) = initial_snapshot(alive_dyn_filter) else {
151        return initial_registration;
152    };
153
154    initial_registration.with_initial_snapshot(initial_snapshot)
155}
156
157fn initial_snapshot(
158    alive_dyn_filter: &DynamicFilterPhysicalExpr,
159) -> Option<InitialDynFilterSnapshot> {
160    let generation = alive_dyn_filter.snapshot_generation();
161    let current = match alive_dyn_filter.current() {
162        Ok(current) => current,
163        Err(error) => {
164            common_telemetry::warn!(error; "Failed to read remote dyn filter initial snapshot");
165            return None;
166        }
167    };
168
169    let payload = match DynFilterPayload::from_datafusion_expr(
170        &current,
171        REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
172    ) {
173        Ok(payload) => payload,
174        Err(error) => {
175            common_telemetry::warn!(error; "Failed to encode remote dyn filter initial snapshot");
176            return None;
177        }
178    };
179
180    // Current DataFusion exposes `wait_complete()`, but no non-blocking completion getter.
181    let is_complete = false;
182    Some(InitialDynFilterSnapshot::new(
183        payload,
184        generation,
185        is_complete,
186    ))
187}
188
189fn build_initial_dyn_filter_regs_for_region(
190    captured_dyn_filters: &[CapturedDynFilter],
191) -> InitialDynFilterRegs {
192    InitialDynFilterRegs::new(
193        captured_dyn_filters
194            .iter()
195            .map(|captured| captured.initial_registration.clone())
196            .collect(),
197    )
198}
199
200pub(crate) fn query_context_with_initial_dyn_filter_regs(
201    query_ctx: &QueryContextRef,
202    region_id: RegionId,
203    captured_dyn_filters: &[CapturedDynFilter],
204) -> QueryContext {
205    let mut region_query_ctx = query_ctx.as_ref().clone();
206    let regs = build_initial_dyn_filter_regs_for_region(captured_dyn_filters);
207    if regs.is_empty() {
208        return region_query_ctx;
209    }
210
211    if let Err(error) = regs.validate_default_bounds() {
212        common_telemetry::warn!(error; "Dropping initial remote dyn filter registrations for region {} that exceed configured bounds", region_id);
213        return region_query_ctx;
214    }
215
216    match regs.to_extension_value() {
217        Ok(serialized) => region_query_ctx.set_extension(
218            INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
219            serialized,
220        ),
221        Err(error) => {
222            common_telemetry::warn!(error; "Failed to serialize initial remote dyn filter registrations");
223        }
224    }
225
226    region_query_ctx
227}
228
229#[cfg(test)]
230mod tests {
231    use std::fmt;
232    use std::hash::{Hash, Hasher};
233
234    use datafusion::execution::TaskContext;
235    use datafusion_common::ScalarValue;
236    use datafusion_expr::ColumnarValue;
237    use datafusion_physical_expr::expressions::{Column, lit};
238    use session::query_id::QueryId;
239    use uuid::Uuid;
240
241    use super::*;
242
243    #[derive(Debug)]
244    struct UnserializableExpr;
245
246    impl fmt::Display for UnserializableExpr {
247        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248            write!(f, "unserializable_expr")
249        }
250    }
251
252    impl Hash for UnserializableExpr {
253        fn hash<H: Hasher>(&self, state: &mut H) {
254            "unserializable_expr".hash(state);
255        }
256    }
257
258    impl PartialEq for UnserializableExpr {
259        fn eq(&self, _other: &Self) -> bool {
260            true
261        }
262    }
263
264    impl Eq for UnserializableExpr {}
265
266    impl datafusion_physical_expr::PhysicalExpr for UnserializableExpr {
267        fn as_any(&self) -> &dyn Any {
268            self
269        }
270
271        fn data_type(
272            &self,
273            _input_schema: &arrow_schema::Schema,
274        ) -> datafusion_common::Result<arrow_schema::DataType> {
275            Ok(arrow_schema::DataType::Boolean)
276        }
277
278        fn nullable(
279            &self,
280            _input_schema: &arrow_schema::Schema,
281        ) -> datafusion_common::Result<bool> {
282            Ok(false)
283        }
284
285        fn evaluate(
286            &self,
287            _batch: &common_recordbatch::DfRecordBatch,
288        ) -> datafusion_common::Result<ColumnarValue> {
289            Ok(ColumnarValue::Scalar(ScalarValue::Boolean(Some(true))))
290        }
291
292        fn children(&self) -> Vec<&Arc<dyn datafusion_physical_expr::PhysicalExpr>> {
293            Vec::new()
294        }
295
296        fn with_new_children(
297            self: Arc<Self>,
298            _children: Vec<Arc<dyn datafusion_physical_expr::PhysicalExpr>>,
299        ) -> datafusion_common::Result<Arc<dyn datafusion_physical_expr::PhysicalExpr>> {
300            Ok(self)
301        }
302
303        fn fmt_sql(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304            write!(f, "{self}")
305        }
306    }
307
308    fn test_query_id(value: u128) -> QueryId {
309        QueryId::from(Uuid::from_u128(value))
310    }
311
312    fn test_remote_dyn_filter_producer_id(value: u64) -> RemoteDynFilterProducerId {
313        RemoteDynFilterProducerId::new(value)
314    }
315
316    fn test_captured_dyn_filter(
317        remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
318        producer_local_ordinal: usize,
319        column_name: &str,
320        column_index: usize,
321    ) -> CapturedDynFilter {
322        build_captured_dyn_filter(
323            remote_dyn_filter_producer_id,
324            producer_local_ordinal,
325            Arc::new(DynamicFilterPhysicalExpr::new(
326                vec![Arc::new(Column::new(column_name, column_index)) as Arc<_>],
327                lit(true) as _,
328            )),
329        )
330        .unwrap()
331    }
332
333    fn test_dyn_filter_with_snapshot_payload(
334        column_name: &str,
335        column_index: usize,
336        payload_bytes: usize,
337    ) -> Arc<DynamicFilterPhysicalExpr> {
338        let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
339            vec![Arc::new(Column::new(column_name, column_index)) as Arc<_>],
340            lit(true) as _,
341        ));
342        dyn_filter
343            .update(lit(ScalarValue::Utf8(Some("x".repeat(payload_bytes)))) as _)
344            .unwrap();
345        dyn_filter
346    }
347
348    #[test]
349    fn capture_remote_dyn_filters_for_pushdown_preserves_parent_filter_ordinals() {
350        let parent_filters = vec![
351            Arc::new(Column::new("service", 0)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
352            Arc::new(DynamicFilterPhysicalExpr::new(
353                vec![Arc::new(Column::new("host", 1)) as Arc<_>],
354                lit(true) as _,
355            )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
356            Arc::new(Column::new("zone", 2)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
357            Arc::new(DynamicFilterPhysicalExpr::new(
358                vec![Arc::new(Column::new("pod", 3)) as Arc<_>],
359                lit(true) as _,
360            )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
361        ];
362
363        let remote_dyn_filter_producer_id = test_remote_dyn_filter_producer_id(42);
364        let captured =
365            capture_remote_dyn_filters_for_pushdown(remote_dyn_filter_producer_id, parent_filters)
366                .captured_dyn_filters;
367
368        assert_eq!(captured.len(), 2);
369        assert_eq!(
370            captured[0].filter_id.remote_dyn_filter_producer_id(),
371            remote_dyn_filter_producer_id
372        );
373        assert_eq!(
374            captured[1].filter_id.remote_dyn_filter_producer_id(),
375            remote_dyn_filter_producer_id
376        );
377        assert_eq!(captured[0].filter_id.producer_ordinal(), 1);
378        assert_eq!(captured[1].filter_id.producer_ordinal(), 3);
379    }
380
381    #[test]
382    fn capture_remote_dyn_filters_for_pushdown_marks_only_valid_initial_regs() {
383        let parent_filters = vec![
384            Arc::new(Column::new("service", 0)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
385            Arc::new(DynamicFilterPhysicalExpr::new(
386                vec![Arc::new(Column::new("host", 1)) as Arc<_>],
387                lit(true) as _,
388            )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
389            Arc::new(Column::new("zone", 2)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
390        ];
391
392        let remote_dyn_filter_producer_id = test_remote_dyn_filter_producer_id(42);
393        let pushdown =
394            capture_remote_dyn_filters_for_pushdown(remote_dyn_filter_producer_id, parent_filters);
395
396        assert_eq!(pushdown.pushed_down, vec![false, true, false]);
397        assert_eq!(pushdown.captured_dyn_filters.len(), 1);
398        assert_eq!(
399            pushdown.captured_dyn_filters[0]
400                .filter_id
401                .remote_dyn_filter_producer_id(),
402            remote_dyn_filter_producer_id
403        );
404        assert_eq!(
405            pushdown.captured_dyn_filters[0]
406                .filter_id
407                .producer_ordinal(),
408            1
409        );
410        assert!(
411            pushdown.captured_dyn_filters[0]
412                .initial_registration
413                .initial_snapshot
414                .is_some()
415        );
416    }
417
418    #[test]
419    fn capture_remote_dyn_filters_for_pushdown_rejects_unencodable_registration() {
420        let parent_filters = vec![Arc::new(DynamicFilterPhysicalExpr::new(
421            vec![Arc::new(UnserializableExpr) as Arc<_>],
422            lit(true) as _,
423        ))
424            as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
425
426        let pushdown = capture_remote_dyn_filters_for_pushdown(
427            test_remote_dyn_filter_producer_id(42),
428            parent_filters,
429        );
430
431        assert_eq!(pushdown.pushed_down, vec![false]);
432        assert!(pushdown.captured_dyn_filters.is_empty());
433    }
434
435    #[test]
436    fn capture_remote_dyn_filters_for_pushdown_attaches_initial_snapshot() {
437        let parent_filters = vec![Arc::new(DynamicFilterPhysicalExpr::new(
438            vec![Arc::new(Column::new("host", 1)) as Arc<_>],
439            lit(true) as _,
440        ))
441            as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
442
443        let pushdown = capture_remote_dyn_filters_for_pushdown(
444            test_remote_dyn_filter_producer_id(42),
445            parent_filters,
446        );
447
448        assert_eq!(pushdown.pushed_down, vec![true]);
449        assert!(
450            pushdown.captured_dyn_filters[0]
451                .initial_registration
452                .initial_snapshot
453                .is_some()
454        );
455    }
456
457    #[test]
458    fn capture_remote_dyn_filters_for_pushdown_attaches_initial_snapshot_after_update() {
459        let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
460            vec![Arc::new(Column::new("host", 1)) as Arc<_>],
461            lit(true) as _,
462        ));
463        dyn_filter.update(lit(false) as _).unwrap();
464        let parent_filters = vec![dyn_filter as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
465
466        let pushdown = capture_remote_dyn_filters_for_pushdown(
467            test_remote_dyn_filter_producer_id(42),
468            parent_filters,
469        );
470
471        assert_eq!(pushdown.pushed_down, vec![true]);
472        let snapshot = pushdown.captured_dyn_filters[0]
473            .initial_registration
474            .initial_snapshot
475            .as_ref()
476            .unwrap();
477        assert_eq!(snapshot.generation, 2);
478        assert!(!snapshot.is_complete);
479        assert!(matches!(
480            snapshot.payload,
481            DynFilterPayload::Datafusion(ref bytes) if !bytes.is_empty()
482        ));
483    }
484
485    #[test]
486    fn capture_remote_dyn_filters_for_pushdown_rejects_oversized_snapshots() {
487        let oversized_total_snapshot_bytes = REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES * 3 / 5;
488        let parent_filters = vec![
489            test_dyn_filter_with_snapshot_payload("host", 0, oversized_total_snapshot_bytes)
490                as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
491            test_dyn_filter_with_snapshot_payload("pod", 1, oversized_total_snapshot_bytes)
492                as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
493        ];
494
495        let pushdown = capture_remote_dyn_filters_for_pushdown(
496            test_remote_dyn_filter_producer_id(42),
497            parent_filters,
498        );
499
500        assert_eq!(pushdown.pushed_down, vec![false, false]);
501        assert!(pushdown.captured_dyn_filters.is_empty());
502    }
503
504    #[test]
505    fn capture_remote_dyn_filters_for_pushdown_rejects_too_many_regs_with_snapshots() {
506        const TOO_MANY_INITIAL_REGS: usize = 65;
507
508        let parent_filters = (0..TOO_MANY_INITIAL_REGS)
509            .map(|ordinal| {
510                test_dyn_filter_with_snapshot_payload(&format!("host_{ordinal}"), ordinal, 1)
511                    as Arc<dyn datafusion::physical_plan::PhysicalExpr>
512            })
513            .collect::<Vec<_>>();
514
515        let pushdown = capture_remote_dyn_filters_for_pushdown(
516            test_remote_dyn_filter_producer_id(42),
517            parent_filters,
518        );
519
520        assert!(pushdown.captured_dyn_filters.is_empty());
521        assert_eq!(pushdown.pushed_down, vec![false; TOO_MANY_INITIAL_REGS]);
522    }
523
524    #[test]
525    fn capture_remote_dyn_filters_for_pushdown_rejects_regs_exceeding_bounds() {
526        const TOO_MANY_INITIAL_REGS: usize = 65;
527
528        let parent_filters = (0..TOO_MANY_INITIAL_REGS)
529            .map(|_| {
530                Arc::new(DynamicFilterPhysicalExpr::new(
531                    vec![Arc::new(Column::new("host", 0)) as Arc<_>],
532                    lit(true) as _,
533                )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>
534            })
535            .collect::<Vec<_>>();
536
537        let pushdown = capture_remote_dyn_filters_for_pushdown(
538            test_remote_dyn_filter_producer_id(42),
539            parent_filters,
540        );
541
542        assert!(pushdown.captured_dyn_filters.is_empty());
543        assert_eq!(pushdown.pushed_down, vec![false; TOO_MANY_INITIAL_REGS]);
544    }
545
546    #[test]
547    fn register_dyn_filters_for_region_reuses_existing_entry() {
548        let registry = QueryDynFilterRegistry::new(test_query_id(1));
549        let captured_dyn_filters = vec![test_captured_dyn_filter(
550            test_remote_dyn_filter_producer_id(42),
551            2,
552            "host",
553            0,
554        )];
555        let first_region_id = RegionId::new(1024, 7);
556        let second_region_id = RegionId::new(1024, 8);
557
558        register_dyn_filters_for_region(&registry, first_region_id, &captured_dyn_filters);
559        register_dyn_filters_for_region(&registry, second_region_id, &captured_dyn_filters);
560
561        assert_eq!(registry.entry_count(), 1);
562        let entry = registry.entries().pop().unwrap();
563        assert_eq!(
564            entry.filter_id().remote_dyn_filter_producer_id(),
565            test_remote_dyn_filter_producer_id(42)
566        );
567        assert_eq!(entry.filter_id().producer_ordinal(), 2);
568        let subscribers = entry.subscribers();
569        assert_eq!(subscribers.len(), 2);
570        assert!(
571            subscribers
572                .iter()
573                .any(|subscriber| subscriber.region_id() == first_region_id)
574        );
575        assert!(
576            subscribers
577                .iter()
578                .any(|subscriber| subscriber.region_id() == second_region_id)
579        );
580    }
581
582    #[test]
583    fn register_dyn_filters_for_region_keeps_independent_producer_ids_distinct() {
584        let registry = QueryDynFilterRegistry::new(test_query_id(1));
585        let region_id = RegionId::new(1024, 7);
586        let make_filter = |remote_dyn_filter_producer_id| {
587            test_captured_dyn_filter(remote_dyn_filter_producer_id, 2, "host", 0)
588        };
589
590        register_dyn_filters_for_region(
591            &registry,
592            region_id,
593            &[make_filter(test_remote_dyn_filter_producer_id(42))],
594        );
595        register_dyn_filters_for_region(
596            &registry,
597            region_id,
598            &[make_filter(test_remote_dyn_filter_producer_id(43))],
599        );
600
601        assert_eq!(registry.entry_count(), 2);
602    }
603
604    #[test]
605    fn query_context_includes_region_initial_dyn_filter_regs() {
606        let captured_dyn_filters = vec![test_captured_dyn_filter(
607            test_remote_dyn_filter_producer_id(42),
608            2,
609            "host",
610            0,
611        )];
612        let region_id = RegionId::new(1024, 7);
613        let query_ctx = QueryContext::arc();
614
615        let region_query_ctx = query_context_with_initial_dyn_filter_regs(
616            &query_ctx,
617            region_id,
618            &captured_dyn_filters,
619        );
620        let extension = region_query_ctx
621            .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
622            .unwrap();
623        let regs = InitialDynFilterRegs::from_extension_value(extension).unwrap();
624        let decoded_children = regs.regs[0]
625            .decode_children(
626                &TaskContext::default(),
627                &arrow_schema::Schema::new(vec![arrow_schema::Field::new(
628                    "host",
629                    arrow_schema::DataType::Utf8,
630                    false,
631                )]),
632                1024,
633            )
634            .unwrap();
635        assert_eq!(regs.regs.len(), 1);
636        assert_eq!(
637            regs.regs[0].filter_id,
638            captured_dyn_filters[0].filter_id.to_string()
639        );
640        assert_eq!(decoded_children.len(), 1);
641        assert!(decoded_children[0].as_any().is::<Column>());
642    }
643
644    #[test]
645    fn query_context_drops_initial_regs_when_duplicate_filter_ids_exceed_bounds() {
646        let captured_dyn_filters = vec![
647            test_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 2, "host", 0),
648            test_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 2, "host", 0),
649        ];
650        let region_id = RegionId::new(1024, 7);
651        let query_ctx = QueryContext::arc();
652
653        let region_query_ctx = query_context_with_initial_dyn_filter_regs(
654            &query_ctx,
655            region_id,
656            &captured_dyn_filters,
657        );
658
659        assert!(
660            region_query_ctx
661                .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
662                .is_none()
663        );
664    }
665}