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

Generate BigInteger literals in CSharpHelper #13911

Merged
merged 1 commit into from
Nov 7, 2018

Conversation

roji
Copy link
Member

@roji roji commented Nov 7, 2018

Needed for code literal generation of NodaTime types. Hopefully this can still go into 2.2?

(if merged into release/2.2, this automatically gets merged into master too, right?)

@ajcvickers
Copy link
Member

@Eilon What's the status on 2.2 builds? Is there time for this to go in? It's very low risk and needed for the Npgsql provider.

Copy link
Member

@Eilon Eilon left a comment

Choose a reason for hiding this comment

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

Let's take it if we can get it in today.

@@ -161,7 +162,8 @@ public CSharpHelper([NotNull] IRelationalTypeMappingSource relationalTypeMapping
{ typeof(TimeSpan), (c, v) => c.Literal((TimeSpan)v) },
{ typeof(uint), (c, v) => c.Literal((uint)v) },
{ typeof(ulong), (c, v) => c.Literal((ulong)v) },
{ typeof(ushort), (c, v) => c.Literal((ushort)v) }
{ typeof(ushort), (c, v) => c.Literal((ushort)v) },
{ typeof(BigInteger), (c, v) => c.Literal((BigInteger)v) }
Copy link
Member

Choose a reason for hiding this comment

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

Wut, no trailing comma??,

Copy link
Member Author

Choose a reason for hiding this comment

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

Just followin' the existing style :)

Needed for code literal generation of NodaTime types
@roji roji force-pushed the generate-literal-biginteger branch from 0372f6e to 79bf006 Compare November 7, 2018 19:39
@roji
Copy link
Member Author

roji commented Nov 7, 2018

Thanks for reviewing and approving so quickly - I amended to use the invariant culture (thanks).

Just to make sure: BigInteger resides in System.Numerics. I can see namespace discovery & inclusion logic in MigrationsCodeGenerator, and I assume it's the user's responsibility to reference System.Numerics from the project containing the migrations - so it seem fine, but I just want to make sure...

If this creates any issues, it's only necessary for generating code literals for NodaTime objects - not very critical (but would definitely be nice to have).

@ajcvickers
Copy link
Member

@bricelam is going to try to get this in today. Thanks @roji.

@bricelam bricelam merged commit 79bf006 into dotnet:release/2.2 Nov 7, 2018
@roji
Copy link
Member Author

roji commented Nov 7, 2018

Thanks for the super quick handling guys....

@roji
Copy link
Member Author

roji commented Nov 19, 2018

After trying to put this to use, it seems we went a bit too quickly with this...

When generating a migration with seeding data for a NodaTime Instant, I get the following expression, which has two problems:

NodaTime.Instant.InstantFromUnixTimeNanoseconds(BigInteger.Parse("1519909261000000000", NumberFormatInfo.InvariantInfo)), "foo" }

In the generated migration and model snapshot, BigInteger and NumberFormatInfo are missing their using statements (System.Numerics, System.Globalization). This is relatively minor, and users can easily add the missing directives as a workaround (but ideally we may need some way to inject them).

A stranger issue is the call to NodaTime.Instant.InstantFromUnixTimeNanoseconds(). My mapping's GenerateCodeLiteral() actually looks like this:

public override Expression GenerateCodeLiteral(object value)
    => Expression.Call(
        typeof(NpgsqlNodaTimeUtils).GetMethod(nameof(NpgsqlNodaTimeUtils.InstantFromUnixTimeNanoseconds), new[] { typeof(BigInteger) }),
        Expression.Constant(NpgsqlNodaTimeUtils.ToUnixTimeNanoseconds((Instant)value)));

A static method is called because some arithmetic needs to be done, and the appropriate expression types aren't supported in CSharpHelper. In any case, InstantFromUnixTimeNanosec() is defined on NpgsqlNodaTimeUtils, but CSharpHelper generates a a call on NodaTime.Instant instead. This seems to come from the following code:

case ExpressionType.Call:
{
    var callExpression = (MethodCallExpression)expression;
    if (callExpression.Method.IsStatic)
    {
        builder
            .Append(Reference(expression.Type, useFullName: true));
    }
    else
    {
        if (!HandleExpression(callExpression.Object, builder))
        {
            return false;
        }
    }

    builder
        .Append('.')
        .Append(callExpression.Method.Name);

For static methods, the reference is generated for the expression type, instead of for the method's declaring type. Unless I'm missing something, this looks like a bug (I can submit a fix).

/cc @bricelam

@ajcvickers
Copy link
Member

@roji For the namespace issue, see #13799. For 2.2 RTM we should namespace-qualify everything in these expressions--but maybe because we added BigInteger directly to CSharp helper with this PR it still needs the the using statement? I added a reference to that issue.

The second issue looks like a clear bug. Could you file an issue for it?

Also, how important is this for the Npgsql provider? We can't get anything in for RTM, but low-risk patch fixes (probably in 2.2.2 at this point) may be possible.

@roji
Copy link
Member Author

roji commented Nov 20, 2018

@ajcvickers opened #13985 for the second bug, will submit a PR soon. At the moment is it blocking NodaTime code literal generation, so NodaTime values cannot be seeded. I've had a couple questions about this, but I can't say it's a total showstopper either. On the other hand, the fix is probably trivial enough for inclusion in a patch (I don't know much about how high you set the bar...).

For the namespace issue, yep, #13799 seems to cover it. It would be nice to add using directives after going through all the literals, rather than fully-qualifying everything and bloating the migration files (although at least in theory we could have the same name in two namespaces, causing a conflict...).

@ajcvickers
Copy link
Member

@roji Thanks. The patch bar has a number of elements, but the one I think might be missing here is high enough customer impact. If we have reports of people hitting this issue it will be more compelling.

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.

4 participants