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

Redo timestamp handling #1992

Merged
merged 1 commit into from
Sep 23, 2021
Merged

Redo timestamp handling #1992

merged 1 commit into from
Sep 23, 2021

Conversation

roji
Copy link
Member

@roji roji commented Sep 19, 2021

Closes #1970
Closes #873
Closes #473
Closes #1974
Closes #1983

@roji roji force-pushed the UntilTheEndOfTime branch 6 times, most recently from bb36860 to be01865 Compare September 20, 2021 09:46
Copy link
Member

@NinoFloris NinoFloris left a comment

Choose a reason for hiding this comment

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

Small nits :shipit:

if (method == SystemClock_GetCurrentInstant)
{
return NpgsqlNodaTimeTypeMappingSourcePlugin.LegacyTimestampBehavior
? _sqlExpressionFactory.AtTimeZone(
Copy link
Member

Choose a reason for hiding this comment

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

So previously there was always a timezone conversion here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not exactly... The old (and now legacy) translation for GetCurrentInstant was NOW() AT TIME ZONE 'UTC' (with constant UTC), which returns a UTC timestamp but typed as timestamp without time zone, since that is how we were mapping Instant. So no timezone conversion - just a PG type conversion.


// We support getting a local DateTime via DateTime.Now (based on PG TimeZone), but there's no way to get a non-UTC
// DateTimeOffset.
nameof(DateTime.Now) when type == typeof(DateTimeOffset)
Copy link
Member

Choose a reason for hiding this comment

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

member.name DateTime.Now can be coming from DateTimeOffset? How does this work?

Copy link
Member Author

Choose a reason for hiding this comment

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

Will clean up (this is just string name matching so no bug or anything)

Copy link
Member Author

Choose a reason for hiding this comment

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

Didn't end up getting cleaner 🤣

storeType = "INT"; // Shorthand that looks better in SQL
var storeType = sqlUnaryExpression.TypeMapping.StoreType switch
{
"integer" => "INT",
Copy link
Member

Choose a reason for hiding this comment

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

Why uppercase?

Copy link
Member Author

Choose a reason for hiding this comment

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

Only because it's been this way... There's already lots of inconsistency around upper/lower case in type and function names... We can look at this separately (don't want to cause even more test changes in this PR :/)

{
var dateTime = (DateTime)value;

if (!NpgsqlTypeMappingSource.LegacyTimestampBehavior && dateTime.Kind == DateTimeKind.Utc)
Copy link
Member

Choose a reason for hiding this comment

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

I'm definitely expecting us to have to loosen this restriction in npgsql. But again, let's wait for the complaints :)

Copy link
Member Author

Choose a reason for hiding this comment

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

We'll see :)

For example, Where(b => b.TimestampTzColumn == new DateTime(2012, 1, 1)) compares a timestamptz (so UTC timestamp) to an unspecified timestamp. This really makes no sense, and the user really should change to comparing against new DateTime(2012, 1, 1, 0, 0, 0, DateTimeKind.Utc). I do think we're doing our users a service by enforcing this, but there may some some cases out of their control which could cause them to block.

Am indeed curious to see the fallout.

#endif

static NpgsqlNodaTimeTypeMappingSourcePlugin()
=> LegacyTimestampBehavior = AppContext.TryGetSwitch("Npgsql.EnableLegacyTimestampBehavior", out var enabled) && enabled;
Copy link
Member

Choose a reason for hiding this comment

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

Not a big fan seeing this compat switch twice, it will probably never happen but you could technically have value drift between the moment this one is initialized in the static constructor and the one in NpgsqlTypeMappingSource.

Copy link
Member Author

Choose a reason for hiding this comment

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

Technically true, but it's very very hard to imagine a non-intentional scenario where this can happen... In general, an application flipping around an appcontext switch is not a normal scenario, and I suspect various other .NET components check switches in multiple parts of the codebase rather than capturing it once...

Do you think we should make the flag a public API in Npgsql? Seems a bit much to me...

@roji roji marked this pull request as ready for review September 23, 2021 13:35
Closes #1970
Closes #873
Closes #473
Closes #1974
Closes #1983
@roji roji enabled auto-merge (squash) September 23, 2021 15:24
@roji roji merged commit aac1a9e into main Sep 23, 2021
@roji roji deleted the UntilTheEndOfTime branch September 23, 2021 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants