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

opt, sqlsmith: fix incorrect output with NULLS LAST in window and aggregate functions #93426

Merged
merged 3 commits into from Dec 14, 2022

Conversation

rytaft
Copy link
Collaborator

@rytaft rytaft commented Dec 12, 2022

opt: fix incorrect output with NULLS LAST in window and aggregate functions

Prior to this commit, window and aggregate functions dropped any NULLS LAST
modifier on their order by clauses. This commit updates the optbuilder to
add an implicit col IS NULL ordering column for each column col that uses
NULLS LAST.

Fixes #91295

Release note (bug fix): Fixed a bug in which the non-default nulls ordering,
NULLS LAST, was ignored in window and aggregate functions. This bug could cause
incorrect query results when NULLS LAST was used, and was introduced in 22.1.0.
This is now fixed.

sqlsmith: added support for randomly using NULLS FIRST or NULLS LAST

Prior to this commit, SQLSmith did not produce queries that used the
non-default nulls ordering. This commit adds support for sometimes using
NULLS FIRST or NULLS LAST with ordering clauses.

Release note: None

@rytaft rytaft requested a review from a team as a code owner December 12, 2022 15:37
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@rytaft rytaft added backport-22.1.x 22.1 is EOL backport-22.2.x Flags PRs that need to be backported to 22.2. labels Dec 12, 2022
Copy link
Collaborator

@mgartner mgartner left a comment

Choose a reason for hiding this comment

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

LGTM

Reviewed 4 of 4 files at r1, 2 of 2 files at r2, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @michae2)

Copy link
Collaborator Author

@rytaft rytaft left a comment

Choose a reason for hiding this comment

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

I updated the code to actually fix the bug, since returning an error won't work due to the null_ordered_last session setting. I think it's still backportable. PTAL. Thanks!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @mgartner and @michae2)

Copy link
Collaborator

@michae2 michae2 left a comment

Choose a reason for hiding this comment

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

Thanks for fixing it! I had some questions, but in general it :lgtm:

Reviewed 1 of 4 files at r1, 8 of 8 files at r3, 2 of 2 files at r4, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @rytaft)


pkg/sql/opt/optbuilder/groupby.go line 728 at r3 (raw file):

			nullsDefaultOrder := b.hasDefaultNullsOrder(o)
			if !nullsDefaultOrder {
				expr := tree.NewTypedIsNullExpr(o.Expr.(tree.TypedExpr))

Do we need to do something special here to handle the case where expr is a tuple, like we did in window functions?


pkg/sql/opt/optbuilder/orderby.go line 287 at r3 (raw file):

			((order.NullsOrder == tree.NullsFirst && order.Direction == tree.Descending) ||
				(order.NullsOrder == tree.NullsLast && order.Direction != tree.Descending))) {
		telemetry.Inc(sqltelemetry.OrderByNullsNonStandardCounter)

Side note, I know this was already here but it seems a little odd that there's nothing to compare it to (i.e. I would expect an equivalent counter for when the default nulls order is used).


pkg/sql/opt/optbuilder/window.go line 434 at r3 (raw file):

					// in other expressions.
					colName := scopeColName("").WithMetadataName(
						fmt.Sprintf("%s_%d_nulls_ordering_%d", funcName, windowIndex+1, j+1),

Should this also use the index of e within cols in case this is a tuple with multiple columns that cannot be referenced?

@rytaft rytaft force-pushed the nulls-last-agg branch 3 times, most recently from bd8350d to aff8ee4 Compare December 13, 2022 22:55
…ctions

Prior to this commit, window and aggregate functions dropped any NULLS LAST
modifier on their order by clauses. This commit updates the optbuilder to
add an implicit `col IS NULL` ordering column for each column `col` that uses
NULLS LAST.

Fixes cockroachdb#91295

Release note (bug fix): Fixed a bug in which the non-default nulls ordering,
NULLS LAST, was ignored in window and aggregate functions. This bug could cause
incorrect query results when NULLS LAST was used, and was introduced in 22.1.0.
This is now fixed.
Prior to this commit, SQLSmith did not produce queries that used the
non-default nulls ordering. This commit adds support for sometimes using
NULLS FIRST or NULLS LAST with ordering clauses.

Release note: None
Prior to this commit, we only had a counter for uses of non-standard
NULLs ordering. This commit adds a counter for standard NULLs ordering
so we can compare the two.

Release note: None
Copy link
Collaborator Author

@rytaft rytaft left a comment

Choose a reason for hiding this comment

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

TFTR! I went down a very deep rabbit hole trying to understand Postgres' behavior with NULLS FIRST/LAST and tuples, and I realized that our current approach of adding an extra ordering column in the optimizer unfortunately just doesn't work very well with tuples (i.e., we'll never be able to completely match Postgres' behavior with the current approach). I opened #93558 to track that issue, but it seems difficult to fix and much lower priority than #91295 (which this PR fixes).

So even if our behavior is somewhat wrong for tuples, at least we are now internally consistent. And this PR should fix the non-tuple cases completely.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @mgartner and @michae2)


pkg/sql/opt/optbuilder/groupby.go line 728 at r3 (raw file):

Previously, michae2 (Michael Erickson) wrote…

Do we need to do something special here to handle the case where expr is a tuple, like we did in window functions?

Great catch! This was actually a pre-existing bug that caused expressions like array_agg((k, v) ORDER BY (k+1, v||'foo')) to fail. Added a test for this too.


pkg/sql/opt/optbuilder/orderby.go line 287 at r3 (raw file):

Previously, michae2 (Michael Erickson) wrote…

Side note, I know this was already here but it seems a little odd that there's nothing to compare it to (i.e. I would expect an equivalent counter for when the default nulls order is used).

Done.


pkg/sql/opt/optbuilder/window.go line 434 at r3 (raw file):

Previously, michae2 (Michael Erickson) wrote…

Should this also use the index of e within cols in case this is a tuple with multiple columns that cannot be referenced?

Done. (I don't think it matters that the metadata name is unique, but fixed just in case...)

Copy link
Collaborator

@michae2 michae2 left a comment

Choose a reason for hiding this comment

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

:lgtm: Nice!

That slack thread definitely taught me a thing or two! 😆

Reviewed 5 of 7 files at r5, 2 of 2 files at r6, 2 of 2 files at r7, 2 of 2 files at r8, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @rytaft)


pkg/sql/opt/optbuilder/groupby.go line 728 at r3 (raw file):

Previously, rytaft (Rebecca Taft) wrote…

Great catch! This was actually a pre-existing bug that caused expressions like array_agg((k, v) ORDER BY (k+1, v||'foo')) to fail. Added a test for this too.

Wow! I was not expecting that, haha. SQL is ridiculous sometimes.


pkg/sql/opt/optbuilder/orderby.go line 287 at r3 (raw file):

Previously, rytaft (Rebecca Taft) wrote…

Done.

Thank you!

Copy link
Collaborator Author

@rytaft rytaft left a comment

Choose a reason for hiding this comment

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

Me too!

bors r+

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @rytaft)

@craig
Copy link
Contributor

craig bot commented Dec 14, 2022

Build succeeded:

@blathers-crl
Copy link

blathers-crl bot commented Dec 14, 2022

Encountered an error creating backports. Some common things that can go wrong:

  1. The backport branch might have already existed.
  2. There was a merge conflict.
  3. The backport branch contained merge commits.

You might need to create your backport manually using the backport tool.


error creating merge commit from b10363d to blathers/backport-release-22.1-93426: POST https://api.github.com/repos/cockroachdb/cockroach/merges: 409 Merge conflict []

you may need to manually resolve merge conflicts with the backport tool.

Backport to branch 22.1.x failed. See errors above.


🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is otan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-22.1.x 22.1 is EOL backport-22.2.x Flags PRs that need to be backported to 22.2.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

sql: disallow ORDER BY NULLS LAST in window functions and aggregate functions
4 participants