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

Release 3.0 roadmap #1764

Closed
17 tasks done
MaceWindu opened this issue Jun 16, 2019 · 67 comments
Closed
17 tasks done

Release 3.0 roadmap #1764

MaceWindu opened this issue Jun 16, 2019 · 67 comments
Milestone

Comments

@MaceWindu
Copy link
Contributor

MaceWindu commented Jun 16, 2019

Approximate list of planned changes for 3.0 release

Removals:

Changes/New Features

Also check this page for list of changes

@MaceWindu MaceWindu added this to the 3.0.0 milestone Jun 16, 2019
@MaceWindu MaceWindu pinned this issue Jun 16, 2019
@genusP
Copy link
Contributor

genusP commented Jun 17, 2019

Please add #832 to roadmap

@MaceWindu
Copy link
Contributor Author

It is actually work in progress already #1756. I didn't added it here, because there are chances to release it before 3.0

@Seanxwy
Copy link

Seanxwy commented Sep 6, 2019

When will it be released

@sdanyliv
Copy link
Member

sdanyliv commented Sep 6, 2019

Approximately in month or two. But you can use it right now without Eager Loading, which needs refreshing my mind :).
https://dev.azure.com/linq2db/linq2db/_packaging?_a=feed&feed=linq2db%40Local

@MaceWindu
Copy link
Contributor Author

MaceWindu commented Oct 17, 2019

We plan to publish preview1 today with already implemented functionality #1936

@detoxhby
Copy link

detoxhby commented Dec 3, 2019

Note: for the last few releases, there were no notifications for the @testers of linq2db, which makes the whole initiative pointless...

I volunteer to test out the RC version when arrives, to make sure the changes would not cause awkwardly big refactors in production systems after the release of 3.0.

@MaceWindu
Copy link
Contributor Author

Finally we are ready to release preview 2 with a lot of new features tomorrow.
We plan to release one more preview with small but important changes:

  • parameters support improvements
  • cleanup of obsolete functionality
  • and some other small fixes

3rd preview will be considered first (and hopefuly last) release candidate for v3.

@MaceWindu MaceWindu modified the milestones: 3.0.0, 3.0.0-rc.0 Apr 27, 2020
@MaceWindu MaceWindu unpinned this issue Apr 27, 2020
@MaceWindu
Copy link
Contributor Author

@linq2db/testers we are almost ready for 3.0rc0 release (hopefully next week, couple of small fixes left). Could you test it?

@detoxhby
Copy link

@MaceWindu we are having a tight deadline next week, I cannot promise anything now sadly :/

@MaceWindu
Copy link
Contributor Author

We are releasing rc0 today. final release scheduled for next week (if @detoxhby will have time to test it).

@MaceWindu MaceWindu modified the milestones: 3.0.0-rc.0, 3.0.0 May 30, 2020
@detoxhby
Copy link

detoxhby commented Jun 1, 2020

SqlClient issue

In projects where we use the new standalone Microsoft.Data.SqlClient package that is a drop in replacement for System.Data.SqlClient, the following type ref exception occours:
(note: stack#2 is the same just thrown from different point)

System.AggregateException : One or more errors occurred. (Could not load type 'System.Data.SqlClient.SqlCommandBuilder' from assembly 'System.Data.SqlClient, Version=4.2.0.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.) (Could not load type 'System.Data.SqlClient.SqlCommandBuilder' from assembly 'System.Data.SqlClient, Version=4.2.0.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.)
---- System.TypeLoadException : Could not load type 'System.Data.SqlClient.SqlCommandBuilder' from assembly 'System.Data.SqlClient, Version=4.2.0.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
---- System.TypeLoadException : Could not load type 'System.Data.SqlClient.SqlCommandBuilder' from assembly 'System.Data.SqlClient, Version=4.2.0.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
----- Inner Stack Trace #1 (System.TypeLoadException) -----
   at System.Reflection.RuntimeAssembly.GetType(QCallAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type, ObjectHandleOnStack keepAlive, ObjectHandleOnStack assemblyLoadContext)
   at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
   at System.Reflection.Assembly.GetType(String name, Boolean throwOnError)
   at LinqToDB.DataProvider.SqlServer.SqlServerProviderAdapter.CreateAdapter(String assemblyName, String clientNamespace, String factoryName)
   at LinqToDB.DataProvider.SqlServer.SqlServerProviderAdapter.GetInstance(SqlServerProvider provider)
   at LinqToDB.DataProvider.SqlServer.SqlServerDataProvider..ctor(String name, SqlServerVersion version, SqlServerProvider provider)
   at LinqToDB.DataProvider.SqlServer.SqlServerTools.<>c.<.cctor>b__33_2()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at LinqToDB.DataProvider.SqlServer.SqlServerTools.GetDataProvider(SqlServerVersion version, SqlServerProvider provider)
   at LinqToDB.DataProvider.SqlServer.SqlServerTools.ProviderDetector(IConnectionStringSettings css, String connectionString)
   at LinqToDB.Data.DataConnection.ConfigurationInfo.<>c__DisplayClass12_0.<GetDataProvider>b__0(Func`3 d)
   at System.Linq.Enumerable.SelectListIterator`2.MoveNext()
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at LinqToDB.Data.DataConnection.ConfigurationInfo.GetDataProvider(IConnectionStringSettings css, String connectionString)
   at LinqToDB.Data.DataConnection.GetDataProvider(String providerName, String connectionString)
   at LinqToDB.Data.DataConnection..ctor(LinqToDbConnectionOptions options)
   at LinqToDB.Data.DataConnection..ctor(LinqToDbConnectionOptionsBuilder builder)
   at LinqToDB.Data.DataConnection..ctor(String providerName, String connectionString)

Installing the original package resolved the problem. We should support the new one as it's offical from Microsoft and will update more regulary than the System.Data. varient.


Grouping issue

I'm working towards to check other parts but GuardGrouping causes headache as 50% of queries are affected and in a lot of cases N+1 is expected and not an issue. Having 1200+ integration tests failing would take numerous time to test by each so I will try to do some match of common patterns.

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

Question: previously .LoadWith() returned ITable<T> but now it returns ILoadWithQueryable<T>; Can I cast this down back to ITable or the hierarchy changed?

It is an issue as in some projects the main table is wrapped in a helpers queryable class that handles aspects like worker thread marshalling and other advanced functionality. This change effectively broke the table wrapper with loadwith as source. Any idea what could be the least-invasive way to refactor this?

@sdanyliv
Copy link
Member

sdanyliv commented Jun 1, 2020

Hierarchy changed.
I think i have to add old style API

db.GetTable<Some>().TableLoadWith(p => p.SomeProp);

It will be suitable?

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

@sdanyliv maybe LoadWithAsTable would be more expressive

@sdanyliv
Copy link
Member

sdanyliv commented Jun 1, 2020

@detoxhby, could you try to set provider name to "Microsoft.Data.SqlClient" it should handle new providers.

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

@sdanyliv it works, but feels unnatural switching from SqlServer (another companion projects (DB migration, DB scaffolding, etc) may be based on this alias - we especially used it in some other projects).
An app switch could be handy to be able to stay on the original alias for the provider but instruct the library to search for the new dependency.

@sdanyliv
Copy link
Member

sdanyliv commented Jun 1, 2020

Try this API

SqlServerTools.Provider = SqlServerProvider.MicrosoftDataSqlClient;

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

Try this API

SqlServerTools.Provider = SqlServerProvider.MicrosoftDataSqlClient;

👍 nice

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

❌ Union-based cross-result with group-by projection error

The query creates cross result of same table by switching Id:Rev with ExcludedId:ExcludedRev, then groups it by Id:ExcludedId to get the last relevant entries based on revisions.
Tried to use .AsSubQuery() on the grouping result before it was used in the join, but didn't change anything (i.e. stack trace was the same).

LinqToDB.LinqToDBException : Expression 'row.DbVersion' is not a field.
at LinqToDB.Linq.Builder.SetOperationBuilder.SetOperationContext.ConvertToSql(Expression expression, Int32 level, ConvertFlags flags)
   at LinqToDB.Linq.Builder.SetOperationBuilder.SetOperationContext.ConvertToIndex(Expression expression, Int32 level, ConvertFlags flags)
   at LinqToDB.Linq.Builder.SetOperationBuilder.SetOperationContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.PassThroughContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.SelectContext.<>c__DisplayClass40_0.<BuildExpression>b__0(IBuildContext ctx, Expression ex, Int32 l)
   at LinqToDB.Linq.Builder.SelectContext.ProcessScalar[T](Expression expression, Int32 level, Func`4 action, Func`1 defaultAction)
   at LinqToDB.Linq.Builder.SelectContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.SelectContext.<>c__DisplayClass40_0.<BuildExpression>b__0(IBuildContext ctx, Expression ex, Int32 l)
   at LinqToDB.Linq.Builder.SelectContext.ProcessScalar[T](Expression expression, Int32 level, Func`4 action, Func`1 defaultAction)
   at LinqToDB.Linq.Builder.SelectContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.PassThroughContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.SelectContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.ExpressionBuilder.TransformExpression(IBuildContext context, Expression expr, Boolean enforceServerSide, String alias)
   at LinqToDB.Linq.Builder.ExpressionBuilder.<>c__DisplayClass77_0.<BuildExpression>b__0(Expression expr)
   at LinqToDB.Expressions.Extensions.Transform(Expression expr, Func`2 func)
   at LinqToDB.Linq.Builder.ExpressionBuilder.BuildExpression(IBuildContext context, Expression expression, Boolean enforceServerSide, String alias)
   at LinqToDB.Linq.Builder.ExpressionBuilder.CorrectConditional(IBuildContext context, Expression expr, Boolean enforceServerSide, String alias)
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertAssignmentArgument(IBuildContext context, Expression expr, MemberInfo memberInfo, Boolean enforceServerSide, String alias)
   at LinqToDB.Linq.Builder.ExpressionBuilder.TransformExpression(IBuildContext context, Expression expr, Boolean enforceServerSide, String alias)
   at LinqToDB.Linq.Builder.ExpressionBuilder.<>c__DisplayClass77_0.<BuildExpression>b__0(Expression expr)
   at LinqToDB.Expressions.Extensions.Transform(Expression expr, Func`2 func)
   at LinqToDB.Linq.Builder.ExpressionBuilder.BuildExpression(IBuildContext context, Expression expression, Boolean enforceServerSide, String alias)
   at LinqToDB.Linq.Builder.SelectContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide)
   at LinqToDB.Linq.Builder.SelectContext.BuildQuery[T](Query`1 query, ParameterExpression queryParameter)
   at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]()
   at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr)
   at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr)
   at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache)
   at LinqToDB.Linq.ExpressionQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()

(used ReadbleExpressions visualizer; stripped unrelated fields)

DbConnection
    .GetTable<QuestionEnemy>()
    .Where(x => ids.Contains(x.QuestionId))
    .Select(
        x => new QuestionEnemyCrossResult
        {
            QuestionId = x.QuestionId,
            QuestionRevision = x.QuestionRevision,
            ExcludedQuestionId = x.ExcludedQuestionId,
            ExcludedQuestionRevision = x.ExcludedQuestionRevision,
            DbVersion = x.DbVersion,
            IsCross = false
        })
    .Union(
        DbConnection
            .GetTable<QuestionEnemy>()
            .Where(x => ids.Contains(x.ExcludedQuestionId))
            .Select(
                x => new QuestionEnemyCrossResult
                {
                    QuestionId = x.ExcludedQuestionId,
                    QuestionRevision = x.ExcludedQuestionRevision,
                    ExcludedQuestionId = x.QuestionId,
                    ExcludedQuestionRevision = x.QuestionRevision,
                    DbVersion = x.DbVersion,
                    IsCross = true
                }))
    .Where(x => ((int?)x.QuestionRevision) <= questionRevision)
    .Join(
        DbConnection
            .GetTable<QuestionEnemy>()
            .Where(x => ids.Contains(x.QuestionId))
            .Select(
                x => new QuestionEnemyCrossResult
                {
                    QuestionId = x.QuestionId,
                    QuestionRevision = x.QuestionRevision,
                    ExcludedQuestionId = x.ExcludedQuestionId,
                    ExcludedQuestionRevision = x.ExcludedQuestionRevision,
                    DbVersion = x.DbVersion,
                    IsCross = false
                })
            .Union(
                DbConnection
                    .GetTable<QuestionEnemy>()
                    .Where(x => ids.Contains(x.ExcludedQuestionId))
                    .Select(
                        x => new QuestionEnemyCrossResult
                        {
                            QuestionId = x.ExcludedQuestionId,
                            QuestionRevision = x.ExcludedQuestionRevision,
                            ExcludedQuestionId = x.QuestionId,
                            ExcludedQuestionRevision = x.QuestionRevision,
                            DbVersion = x.DbVersion,
                            IsCross = true
                        }))
            .Where(x => ((int?)x.QuestionRevision) <= questionRevision)
            .GroupBy(x => new 
            {
                QuestionId = x.QuestionId,
                ExcludedQuestionId = x.ExcludedQuestionId
            })
            .Select(
                x => new QuestionEnemy
                {
                    QuestionId = x.Key.QuestionId,
                    QuestionRevision = x.Max(y => y.QuestionRevision),
                    ExcludedQuestionId = x.Key.ExcludedQuestionId,
                    ExcludedQuestionRevision = x.Max(y => y.ExcludedQuestionRevision)
                }),
        row => new 
        {
            QuestionId = row.QuestionId,
            QuestionRevision = row.QuestionRevision,
            ExcludedQuestionId = row.ExcludedQuestionId,
            ExcludedQuestionRevision = row.ExcludedQuestionRevision
        },
        affectedRevision => new 
        {
            QuestionId = affectedRevision.QuestionId,
            QuestionRevision = affectedRevision.QuestionRevision,
            ExcludedQuestionId = affectedRevision.ExcludedQuestionId,
            ExcludedQuestionRevision = affectedRevision.ExcludedQuestionRevision
        },
        (row, affectedRevision) => row)
    .Join(
        DbConnection.GetTable<QuestionId>(),
        enemy => enemy.ExcludedQuestionId,
        question => question.Id,
        (enemy, question) => new QuestionEnemyCrossResultWithCurrentEQR
        {
            QuestionId = enemy.QuestionId,
            QuestionRevision = enemy.QuestionRevision,
            ExcludedQuestionId = enemy.ExcludedQuestionId,
            ExcludedQuestionRevision = enemy.ExcludedQuestionRevision,
            LastExcludedQuestionRevision = question.Revision,
            DbVersion = enemy.DbVersion
        })

@sdanyliv
Copy link
Member

sdanyliv commented Jun 1, 2020

I have reproduced, working on fix.

@sdanyliv
Copy link
Member

sdanyliv commented Jun 1, 2020

@detoxhby, you have stripped too much. There are a lot of such reasonable exceptions.

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

❌ Eager-loading related issue

See #2249

@detoxhby
Copy link

detoxhby commented Jun 1, 2020

@detoxhby, you have stripped too much. There are a lot of such reasonable exceptions.

@sdanyliv edited the expression in corresponding comment; now only extra marker (bool) and auditable fields are stripped out

@detoxhby
Copy link

detoxhby commented Jun 3, 2020

could you please re-run tests on current master? I have made several fixes yesterday and they may cause regressions.
Nugets are ready.

Yes, will do it later today or tomorrow (I'm on the road currently).

@sdanyliv
Copy link
Member

sdanyliv commented Jun 3, 2020

Just found that you have mentioned this function
ITable<T> DisableGroupingGuard<T>(this ITable<T> source)
Why it is more safe than IQueryable variant? I think both are dangerous.

@detoxhby
Copy link

detoxhby commented Jun 3, 2020

Because it also represents a real intention of doing this at the root level and would prevent developers to append the DisableGroupingGuard call later on an uknown IQueryable source
(and by unkown I mean it is not trivial or not even known from where that queryable source comes from or what produced it - mostly because it is given by a lower component/layer).

For real use cases, it would be wrapped inside a repository's base call where a specific pre-configurator would use it, not something the developers would do in app-code.
On the usefullness part: it would allow per-entity (per-table) fine-grained exclusion of guard usage instead of global disable.

Maybe we should drop this and only include the IGrouping version to prevent confusion for now.

@detoxhby
Copy link

detoxhby commented Jun 4, 2020

could you please re-run tests on current master? I have made several fixes yesterday and they may cause regressions.
Nugets are ready.

Yes, will do it later today or tomorrow (I'm on the road currently).

v3.0.0-rc2243 ✅ seems good, but due to #2248 (comment) I'm still only able to test 1/5 of the projects because the LoadWith behavior blocks essential parts of the applications that I cannot overcome in any way

@sdanyliv
Copy link
Member

sdanyliv commented Jun 4, 2020

If you prepare small non working sample with your LoadWith extension, i'll check.

@detoxhby
Copy link

detoxhby commented Jun 4, 2020

If you prepare small non working sample with your LoadWith extension, i'll check.

Sadly, can't. It is just chaotic why the exact same LoadWith calls work (=loads the referenced data) into the relations while others simply stays empty without any error. I have no time to trace it down, thus I cannot prepare an exact reproducing environment. Currently the errors rise at fully random places but so far all of them was related to an earlier LoadWith (that produced empty result) that wasn't handled explicitly (so no .Any() or null checks present, because it should contain data based on preconditions).

Gonna try to delegate a few hours at the weekend, but currently we have a deadline and deployment for the next weeks that steals all of energy. Will try my best to solve this.

@MaceWindu
Copy link
Contributor Author

We decided to release rc1 tomorrow or early next week due to large amount of fixes since rc0.

@detoxhby
Copy link

I wasn't able to provide additional information, so I will retry the whole process with rc1 and see how it works. If the results will be the same, I will focus on a separate application to reproduce the situation with empty loadwith behaviour.

@sdanyliv
Copy link
Member

sdanyliv commented Jun 15, 2020

For reproducing empty LoadWith, i will need SQL and model. Possibly we can not construct final collection because some property types has bad Equals implementations.

@detoxhby
Copy link

ℹ️ FYI: new Microsoft.Data.SqlClient 2.0 MARS is broken with the 2.x branch (haven't tested with 3.0 yet)
System.ArgumentException: 'Keyword not supported: 'multiple active result sets'.'
https://devblogs.microsoft.com/azure-sql/microsoft-data-sqlclient-2-0-0-is-now-available/

@MaceWindu
Copy link
Contributor Author

MaceWindu commented Jun 24, 2020

Not sure I get you. Microsoft.Data.SqlClient support was added only in v3, so v2 shouldn't work with it. Also we have tests with MARS and recently updated our tests to v2 client and don't see any failures

@detoxhby
Copy link

Not sure I get you. Microsoft.Data.SqlClient support was added only in v3, so v2 shouldn't work with it. Also we have tests with MARS and recently updated our tests to v2 client and don't see any failures

Finished the problem analysis and found a really strange behaviour:

  • code that bootstraps the DataConnection with custom connection string uses Microsoft.Data.SqlClient
  • SqlConnectionStringBuilder are used with .MultipleActiveResultSets = true
  • with version < 2.0.0 the resulting connection string contains MultipleActiveResultSets=True;, but...
  • with version >= 2.0.0 the result connection string contains Multiple Active Result Sets=True;

Like you said: as of 2.x version of linq2db does not use the new SqlClient package, it couldn't handle the new format interally.


The problem may not directly related to the project but could be a main pitfall for others with similar approach (using new SqlClient package in application, but for some reason stays on v2.x version of linq2db). A simple info line in release notes would be sufficient to warn people about connection string format differences.

@MaceWindu
Copy link
Contributor Author

2.0.0 added more connection string properties aliases, but old aliases still work https://github.com/dotnet/SqlClient/blob/master/release-notes/2.0/2.0.0.md#new-connection-string-property-synonyms

@detoxhby
Copy link

2.0.0 added more connection string properties aliases, but old aliases still work https://github.com/dotnet/SqlClient/blob/master/release-notes/2.0/2.0.0.md#new-connection-string-property-synonyms

That's right, but by-default SqlConnectionStringBuilder generates the new format and that is not correct for System.Data.SqlClient based linq2db provider (talking about v2.x of linq2db, not v3.0).

@MaceWindu
Copy link
Contributor Author

So... user use Microsoft.Data.SqlClient 2.0.0 to create connection string to use with System.Data.SqlClient (or Microsoft.Data.SqlClient < 2.0.0)? Still don't see how it could be our fault.

@detoxhby
Copy link

So... user use Microsoft.Data.SqlClient 2.0.0 to create connection string to use with System.Data.SqlClient (or Microsoft.Data.SqlClient < 2.0.0)? Still don't see how it could be our fault.

Not fault, but consequence.

It's a legit scenario and even if linq2db does nothing wrong, the error still occour "inside" linq2db and it's easy to misinterpret what really happens under the hood.

I've just tried to provide real-life aspects of this problem, the decision is yours to indicate it or not of course.

@MaceWindu
Copy link
Contributor Author

I don't think it worth mentioning. It's quite unusual configuration

@detoxhby
Copy link

detoxhby commented Jul 1, 2020

(edited)

see #2306 #2307

@MaceWindu
Copy link
Contributor Author

@detoxhby could you create separate issues?
BTW, we decided to postpone release for a week and publish another rc this week

@detoxhby
Copy link

detoxhby commented Jul 1, 2020

could you create separate issues?

@MaceWindu for each one separately or only one aggregated?

@MaceWindu
Copy link
Contributor Author

each issue separately. Discussing different issues in single thread results in hard to track conversation

@detoxhby
Copy link

detoxhby commented Jul 1, 2020

(edited)

see #2309

@sdanyliv
Copy link
Member

sdanyliv commented Jul 1, 2020

Post a new issue with simple reproducible steps.

@Shane32
Copy link
Contributor

Shane32 commented Jul 1, 2020

FYI SQL Server 2000 cannot be accessed from tests running within .Net Core -- they only work from .Net 4.6. The error message says that the version of SQL Server is not supported. I'm guessing this is due to the switch to Microsoft.Data.SqlClient. Just something to put in the release notes.

@sdanyliv
Copy link
Member

sdanyliv commented Jul 1, 2020

@Shane32, you've just resurrected Sql Server 2000 in our minds ;)

@Shane32
Copy link
Contributor

Shane32 commented Jul 1, 2020

I spent way too much time installing that to test my code with. It probably wasn't worth it - lol!

@sdanyliv
Copy link
Member

sdanyliv commented Jul 1, 2020

It was experience ))
Library has a long history so it supports a lot of outdated engines. Anyway thanks for investigation, it should be mentioned I think.

@MaceWindu
Copy link
Contributor Author

Closing as we plan to release today

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants