From 762605592fcf6d05432e7a384b114196509e25d1 Mon Sep 17 00:00:00 2001 From: Ben Bellick Date: Wed, 4 Mar 2026 11:59:15 -0500 Subject: [PATCH 1/3] feat: add has_overlap function to functions_set.yaml (#986) --- extensions/functions_set.yaml | 37 +++++++++++++++++++++++++++ tests/cases/set/has_overlap.test | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/cases/set/has_overlap.test diff --git a/extensions/functions_set.yaml b/extensions/functions_set.yaml index 3331b29f0..5d835d3d5 100644 --- a/extensions/functions_set.yaml +++ b/extensions/functions_set.yaml @@ -26,3 +26,40 @@ scalar_functions: values: [ NAN_IS_NAN, NAN_IS_NOT_NAN ] nullability: DECLARED_OUTPUT return: i64? + - + name: "has_overlap" + description: > + Determines whether two lists share any common elements. + + Returns `true` if the two lists have at least one non-null element in common, + `false` if they definitely do not, and the behavior when null elements are + present but no non-null overlap exists is controlled by the `null_handling` + option. + + If either input list is `NULL`, returns `NULL`. + + If either input list is empty, returns `false`. + impls: + - args: + - name: left + value: list + - name: right + value: list + options: + null_handling: + description: > + Controls how null elements affect the result when no non-null + elements overlap. + + - THREE_VALUED: Returns NULL when null elements are present in + both lists but no non-null overlap is found. + + - IGNORE_NULLS: Skips null elements entirely so the result is + always true or false. + + - NULL_EQUALS_NULL: Treats null elements as equal to each + other, so if both lists contain null that counts as an + overlap. + values: [ THREE_VALUED, IGNORE_NULLS, NULL_EQUALS_NULL ] + nullability: DECLARED_OUTPUT + return: boolean? diff --git a/tests/cases/set/has_overlap.test b/tests/cases/set/has_overlap.test new file mode 100644 index 000000000..8ee9b457b --- /dev/null +++ b/tests/cases/set/has_overlap.test @@ -0,0 +1,43 @@ +### SUBSTRAIT_SCALAR_TEST: v1.0 +### SUBSTRAIT_INCLUDE: '/extensions/functions_set.yaml' + +# basic_overlap: Non-null overlap exists +has_overlap([1, 2, 3]::list, [3, 4, 5]::list) [null_handling:THREE_VALUED] = true::bool +has_overlap([1, 2, 3]::list, [3, 4, 5]::list) [null_handling:IGNORE_NULLS] = true::bool +has_overlap([1, 2, 3]::list, [3, 4, 5]::list) [null_handling:NULL_EQUALS_NULL] = true::bool + +# basic_no_overlap: No overlap exists +has_overlap([1, 2, 3]::list, [4, 5, 6]::list) [null_handling:THREE_VALUED] = false::bool +has_overlap([1, 2, 3]::list, [4, 5, 6]::list) [null_handling:IGNORE_NULLS] = false::bool +has_overlap([1, 2, 3]::list, [4, 5, 6]::list) [null_handling:NULL_EQUALS_NULL] = false::bool + +# duplicates: Duplicate elements +has_overlap([1, 1, 2]::list, [1, 3]::list) [null_handling:THREE_VALUED] = true::bool +has_overlap([1, 1, 2]::list, [1, 3]::list) [null_handling:IGNORE_NULLS] = true::bool +has_overlap([1, 1, 2]::list, [1, 3]::list) [null_handling:NULL_EQUALS_NULL] = true::bool + +# empty_right: One list is empty +has_overlap([1, 2, 3]::list, []::list) [null_handling:THREE_VALUED] = false::bool +has_overlap([1, 2, 3]::list, []::list) [null_handling:IGNORE_NULLS] = false::bool +has_overlap([1, 2, 3]::list, []::list) [null_handling:NULL_EQUALS_NULL] = false::bool + +# both_empty: Both lists are empty +has_overlap([]::list, []::list) [null_handling:THREE_VALUED] = false::bool +has_overlap([]::list, []::list) [null_handling:IGNORE_NULLS] = false::bool +has_overlap([]::list, []::list) [null_handling:NULL_EQUALS_NULL] = false::bool + +# null_elements_with_non_null_overlap: Null elements present with a non-null overlap +has_overlap([1, null, 3]::list, [3, 4]::list) [null_handling:THREE_VALUED] = true::bool +has_overlap([1, null, 3]::list, [3, 4]::list) [null_handling:IGNORE_NULLS] = true::bool +has_overlap([1, null, 3]::list, [3, 4]::list) [null_handling:NULL_EQUALS_NULL] = true::bool + +# null_elements_no_non_null_overlap: Null elements in one list, no non-null overlap +has_overlap([1, null, 3]::list, [4, 5]::list) [null_handling:THREE_VALUED] = null::bool +has_overlap([1, null, 3]::list, [4, 5]::list) [null_handling:IGNORE_NULLS] = false::bool +has_overlap([1, null, 3]::list, [4, 5]::list) [null_handling:NULL_EQUALS_NULL] = false::bool + +# null_elements_in_both: Null elements in both lists, no non-null overlap +has_overlap([1, null]::list, [null, 4]::list) [null_handling:THREE_VALUED] = null::bool +has_overlap([1, null]::list, [null, 4]::list) [null_handling:IGNORE_NULLS] = false::bool +has_overlap([1, null]::list, [null, 4]::list) [null_handling:NULL_EQUALS_NULL] = true::bool + From 062556dc4b2e674fbcc58a8fdaab4da8fe26685b Mon Sep 17 00:00:00 2001 From: Ben Bellick Date: Thu, 5 Mar 2026 17:24:42 -0500 Subject: [PATCH 2/3] feat: move has_overlap from functions_set to functions_list --- extensions/functions_list.yaml | 37 ++++++++++++++++++++++ extensions/functions_set.yaml | 36 --------------------- tests/cases/{set => list}/has_overlap.test | 2 +- 3 files changed, 38 insertions(+), 37 deletions(-) rename tests/cases/{set => list}/has_overlap.test (98%) diff --git a/extensions/functions_list.yaml b/extensions/functions_list.yaml index f7776350f..d44b9d2c3 100644 --- a/extensions/functions_list.yaml +++ b/extensions/functions_list.yaml @@ -130,3 +130,40 @@ scalar_functions: value: func boolean?> nullability: DECLARED_OUTPUT return: boolean? + + - name: "has_overlap" + description: >- + Determines whether two lists share any common elements. + + Returns `true` if the two lists have at least one non-null element in common, + `false` if they definitely do not, and the behavior when null elements are + present but no non-null overlap exists is controlled by the `null_handling` + option. + + If either input list is `NULL`, returns `NULL`. + + If either input list is empty, returns `false`. + impls: + - args: + - name: left + value: list + - name: right + value: list + options: + null_handling: + description: >- + Controls how null elements affect the result when no non-null + elements overlap. + + - THREE_VALUED: Returns NULL when null elements are present in + both lists but no non-null overlap is found. + + - IGNORE_NULLS: Skips null elements entirely so the result is + always true or false. + + - NULL_EQUALS_NULL: Treats null elements as equal to each + other, so if both lists contain null that counts as an + overlap. + values: [THREE_VALUED, IGNORE_NULLS, NULL_EQUALS_NULL] + nullability: DECLARED_OUTPUT + return: boolean? diff --git a/extensions/functions_set.yaml b/extensions/functions_set.yaml index 5d835d3d5..08495415c 100644 --- a/extensions/functions_set.yaml +++ b/extensions/functions_set.yaml @@ -26,40 +26,4 @@ scalar_functions: values: [ NAN_IS_NAN, NAN_IS_NOT_NAN ] nullability: DECLARED_OUTPUT return: i64? - - - name: "has_overlap" - description: > - Determines whether two lists share any common elements. - - Returns `true` if the two lists have at least one non-null element in common, - `false` if they definitely do not, and the behavior when null elements are - present but no non-null overlap exists is controlled by the `null_handling` - option. - - If either input list is `NULL`, returns `NULL`. - If either input list is empty, returns `false`. - impls: - - args: - - name: left - value: list - - name: right - value: list - options: - null_handling: - description: > - Controls how null elements affect the result when no non-null - elements overlap. - - - THREE_VALUED: Returns NULL when null elements are present in - both lists but no non-null overlap is found. - - - IGNORE_NULLS: Skips null elements entirely so the result is - always true or false. - - - NULL_EQUALS_NULL: Treats null elements as equal to each - other, so if both lists contain null that counts as an - overlap. - values: [ THREE_VALUED, IGNORE_NULLS, NULL_EQUALS_NULL ] - nullability: DECLARED_OUTPUT - return: boolean? diff --git a/tests/cases/set/has_overlap.test b/tests/cases/list/has_overlap.test similarity index 98% rename from tests/cases/set/has_overlap.test rename to tests/cases/list/has_overlap.test index 8ee9b457b..bd44e9a0d 100644 --- a/tests/cases/set/has_overlap.test +++ b/tests/cases/list/has_overlap.test @@ -1,5 +1,5 @@ ### SUBSTRAIT_SCALAR_TEST: v1.0 -### SUBSTRAIT_INCLUDE: '/extensions/functions_set.yaml' +### SUBSTRAIT_INCLUDE: '/extensions/functions_list.yaml' # basic_overlap: Non-null overlap exists has_overlap([1, 2, 3]::list, [3, 4, 5]::list) [null_handling:THREE_VALUED] = true::bool From 25432e22cb4734e90ba7b0543b13b0d6333224d6 Mon Sep 17 00:00:00 2001 From: Ben Bellick Date: Fri, 6 Mar 2026 11:39:48 -0500 Subject: [PATCH 3/3] feat: add null list test cases for has_overlap --- tests/cases/list/has_overlap.test | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cases/list/has_overlap.test b/tests/cases/list/has_overlap.test index bd44e9a0d..6b5964cac 100644 --- a/tests/cases/list/has_overlap.test +++ b/tests/cases/list/has_overlap.test @@ -26,6 +26,21 @@ has_overlap([]::list, []::list) [null_handling:THREE_VALUED] = false:: has_overlap([]::list, []::list) [null_handling:IGNORE_NULLS] = false::bool has_overlap([]::list, []::list) [null_handling:NULL_EQUALS_NULL] = false::bool +# null_left_list: Null left list returns null +has_overlap(null::list, [1, 2, 3]::list) [null_handling:THREE_VALUED] = null::bool +has_overlap(null::list, [1, 2, 3]::list) [null_handling:IGNORE_NULLS] = null::bool +has_overlap(null::list, [1, 2, 3]::list) [null_handling:NULL_EQUALS_NULL] = null::bool + +# null_right_list: Null right list returns null +has_overlap([1, 2, 3]::list, null::list) [null_handling:THREE_VALUED] = null::bool +has_overlap([1, 2, 3]::list, null::list) [null_handling:IGNORE_NULLS] = null::bool +has_overlap([1, 2, 3]::list, null::list) [null_handling:NULL_EQUALS_NULL] = null::bool + +# both_null_lists: Both lists null returns null +has_overlap(null::list, null::list) [null_handling:THREE_VALUED] = null::bool +has_overlap(null::list, null::list) [null_handling:IGNORE_NULLS] = null::bool +has_overlap(null::list, null::list) [null_handling:NULL_EQUALS_NULL] = null::bool + # null_elements_with_non_null_overlap: Null elements present with a non-null overlap has_overlap([1, null, 3]::list, [3, 4]::list) [null_handling:THREE_VALUED] = true::bool has_overlap([1, null, 3]::list, [3, 4]::list) [null_handling:IGNORE_NULLS] = true::bool