Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Windowing] Handle null values in partitions #141

Closed
wants to merge 1 commit into from

Conversation

ohaibbq
Copy link
Contributor

@ohaibbq ohaibbq commented Jan 29, 2024

This inserts a placeholder value to use for partitioning when rows contain a null value.

Closes #139 #86

@codecov-commenter
Copy link

Codecov Report

Merging #141 (7a7d935) into main (7d3a82f) will decrease coverage by 0.04%.
The diff coverage is 100.00%.

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #141      +/-   ##
==========================================
- Coverage   45.82%   45.78%   -0.04%     
==========================================
  Files          47       47              
  Lines       17800    17804       +4     
==========================================
- Hits         8156     8152       -4     
- Misses       8182     8193      +11     
+ Partials     1462     1459       -3     

@@ -274,6 +274,9 @@ type WindowFuncStatus struct {
OrderBy []*WindowOrderBy
}

// windowNilPartitionValue Placeholder value for nil
const windowNilPartitionValue = StringValue("^^^ZETASQLITE_NIL^^^")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@goccy While exploring other issues, it seems this case comes up often.

Does it make sense to introduce a new NilValue class instead?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NULL is not the first class's value. So I want to deal with this by handling null properly.

@@ -274,6 +274,9 @@ type WindowFuncStatus struct {
OrderBy []*WindowOrderBy
}

// windowNilPartitionValue Placeholder value for nil
const windowNilPartitionValue = StringValue("^^^ZETASQLITE_NIL^^^")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NULL is not the first class's value. So I want to deal with this by handling null properly.

if v.Value != nil {
opt.Partitions = append(opt.Partitions, v.Value.(Value))
} else {
opt.Partitions = append(opt.Partitions, windowNilPartitionValue)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just use nil instead of windowNilPartitionValue ?

Copy link
Contributor Author

@ohaibbq ohaibbq Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would strings.Join("_", []string{"a", nil, "c"}) evaluate to?

The intention is that windowed rows that share common nil columns are partitioned together.

WITH toks as (
  SELECT 'a' as prop1, null as prop2, 'aa' as prop3
  UNION ALL SELECT 'a' as prop1, 'aa' as prop2, null as prop3
)
SELECT prop1, ROW_NUMBER() over (PARTITION BY prop2, prop3) AS rn FROM toks

Expected:

prop1 rn
a 1
a 1

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A guard expression against nil must be inserted before the join process.

func (s *WindowFuncStatus) Partition() (string, error) {
	partitions := make([]string, 0, len(s.Partitions))
	for _, p := range s.Partitions {
                if p == nil {
                  continue
                }
		text, err := p.ToString()
		if err != nil {
			return "", err
		}
		partitions = append(partitions, text)
	}
	return strings.Join(partitions, "_"), nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the query above, wouldn't that result in the following?

prop1 rn
a 1
a 2

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Then it looks like we should add constant NullValue structure.

Example.

  • value.go
type NullValue struct {
  zeroValue Value
}

NullValue should have the original type information, so it should either have a zero value or reflect.Type .
If NULL value is integer type, initialize as follows

&NullValue{zeroValue: IntValue(0)}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to do this as I think it is the right approach, too.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you !! Generics seems to be a better choice. 😃

type NullValue[T Value] struct {
  zeroValue T
}

@ohaibbq
Copy link
Contributor Author

ohaibbq commented Feb 17, 2024

Closing in favor of #169!

@ohaibbq ohaibbq closed this Feb 17, 2024
@ohaibbq ohaibbq deleted the dan/window-partition-nils branch March 28, 2024 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Windowing] Crash when a window partition has null-value
3 participants