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

Possible mergeable classes for merging code bases #1261

Open
DavoudEshtehari opened this issue Sep 11, 2021 · 20 comments
Open

Possible mergeable classes for merging code bases #1261

DavoudEshtehari opened this issue Sep 11, 2021 · 20 comments
Assignees
Labels
➕ Code Health Changes related to source code improvements

Comments

@DavoudEshtehari
Copy link
Member

DavoudEshtehari commented Sep 11, 2021

The main aim of this ticket is to clarify the project progress and having contribution with who is interested in it.

At the first step, we've prepared a list of possible mergeable files with their types which maybe need some pruning. Then, priority could be declared before starting to merge.

Mergable files list
File & PR Type Group Priority
DbConnectionStringCommon.cs #1265 DbConnectionStringDefaults DbConnectionStringKeywords DbConnectionStringSynonyms DbConnectionStringBuilderUtil Common  1
DbConnectionOptions.Common.cs (core) DbConnectionOptions.cs #1279 DbConnectionOptions KEY SYNONYM Common  1
AdapterUtil.cs AdapterUtil.Drivers.cs (core) AdapterUtil.SqlClient.cs (core) #1306 ADP Common  1
StringsHelper.cs #1288 StringsHelper Common 1
DbConnectionClosed.cs DbConnectionClosed DbConnectionBusy DbConnectionClosedBusy DbConnectionClosedConnecting DbConnectionClosedNeverOpened DbConnectionClosedPreviouslyOpened DbConnectionOpenBusy ProviderBase  
DbConnectionInternal.cs DbConnectionInternal ProviderBase  
DbConnectionFactory.cs DbConnectionFactory ProviderBase  
DbConnectionPool.cs PendingGetConnection PoolWaitHandles State TransactedConnectionList TransactedConnectionPool ProviderBase  
DbConnectionPoolGroup.cs #1371 DbConnectionPoolGroup ProviderBase  
DbConnectionPoolIdentity.cs DbConnectionPoolIdentity.Unix.cs (core) DbConnectionPoolIdentity.Windows.cs (core) DbConnectionPoolIdentity ProviderBase  
DbMetaDataFactory.cs #1278 DbMetaDataFactory ProviderBase  
DbReferenceCollection.cs #2403 DbReferenceCollection CollectionEntry ProviderBase
TimeoutTimer.cs #1273 TimeoutTimer ProviderBase  
SQLResource.cs #1276 SQLResource SqlTypes  
SqlFileStream.cs (fx) SqlFileStream.Windows.cs (core) SqlFileStream SqlTypes  
MetadataUtilsSmi.cs #1339 MetadataUtilsSmi SqlClient.Server  
SmiEventSink.cs #1324 SmiEventSink SqlClient.Server  
SmiEventSink_Default.cs #1324 SmiEventSink_Default SqlClient.Server  
SmiMetaDataProperty.cs #1320 SmiDefaultFieldsProperty SmiMetaDataProperty SmiMetaDataPropertyCollection SmiOrderProperty SmiPropertySelector SmiUniqueKeyProperty SqlClient.Server  
SmiTypedGetterSetter.cs #1321 SmiTypedGetterSetter SqlClient.Server  
SmiXetterAccessMap.cs #1310 SmiXetterAccessMap SqlClient.Server  
SqlDataRecord.cs #1309 SqlDataRecord SqlClient.Server  
SqlSer.cs #1313 BinarySerializeSerializer DummyStream NormalizedSerializer SerializationHelperSql9 Serializer SqlClient.Server  
ValueUtilsSmi.cs #1326 ValueUtilsSmi SqlClient.Server  
AlwaysEncryptedHelperClasses.cs (core) TdsParserHelperClasses.cs _SqlMetaData _SqlMetaDataSet _SqlMetaDataSetCollection _SqlRPC CallbackType EncryptionOptions PreLoginHandshakeStatus PreLoginOptions RunBehavior TdsParserState FederatedAuthenticationFeatureExtensionData SqlCollation RoutingInfo SqlEnvChange SqlLogin SqlLoginAck SqlFedAuthInfo SqlFedAuthToken SqlMetaDataPriv SqlMetaDataXmlSchemaCollection SqlMetaDataUdt SqlReturnValue MultiPartTableName SslProtocolsHelper SqlClient  
AlwaysEncryptedKeyConverter.Cng.cs (fx) AlwaysEncryptedKeyConverter.CrossPlatform.cs (core) KeyConverter SqlClient  
LocalDBAPI.cs LocalDBAPI.Common.cs (core) LocalDBAPI.uap.cs (core) LocalDBAPI.Unix.cs (core) LocalDBAPI.Windows.cs (core) LocalDBAPI SqlClient  
SimulatorEnclaveProvider.cs (fx) SimulatorEnclaveProvider.NetCoreApp.cs (core) #1419 SimulatorEnclaveProvider SqlClient  
SqlAuthenticationProviderManager.cs SqlAuthenticationProviderManager.NetCoreApp.cs (core) SqlAuthenticationProviderManager.NetStandard.cs (core) SqlAuthenticationProviderManager SqlAuthenticationInitializer SqlAuthenticationProviderConfigurationSection SqlClientAuthenticationProviderConfigurationSection SqlClient  
SqlBuffer.cs #1438 SqlBuffer SqlClient  
SqlBulkCopy.cs _ColumnMapping Row Result BulkCopySimpleResultSet SqlBulkCopy SqlClient  
SqlBulkCopyColumnMappingCollection.cs #1285 SqlBulkCopyColumnMappingCollection SqlClient  
SqlCachedBuffer.cs #1280 SqlCachedBuffer SqlClient  
SqlClientFactory.cs #2369 SqlClientFactory SqlClient  
SqlClientMetaDataCollectionNames.cs #1287 SqlClientMetaDataCollectionNames SqlClient  
SqlColumnEncryptionCertificateStoreProvider.Windows.cs (core) SqlColumnEncryptionCertificateStoreProvider.cs (fx) SqlColumnEncryptionCertificateStoreProvider.Unix.cs (core) SqlColumnEncryptionCertificateStoreProvider SqlClient  
SqlColumnEncryptionCngProvider.cs (fx) SqlColumnEncryptionCngProvider.Windows.cs (core) SqlColumnEncryptionCngProvider.Unix.cs (core) SqlColumnEncryptionCngProvider SqlClient  
SqlColumnEncryptionCspProvider.cs (fx) SqlColumnEncryptionCspProvider.Windows.cs (core) SqlColumnEncryptionCspProvider.Unix.cs (core) SqlColumnEncryptionCspProvider SqlClient  
SqlColumnEncryptionEnclaveProvider.cs SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs (core) SqlColumnEncryptionEnclaveProvider SqlClient  
SqlCommand.cs SqlCommand SqlClient  
SqlCommandBuilder.cs #1284 SqlCommandBuilder SqlClient  
SqlCommandSet.cs #1286 SqlCommandSet SqlClient  
SqlConnection.cs SqlConnectionHelper.cs SqlConnection SqlClient  
SqlConnectionFactory.cs SqlConnectionFactory.AssemblyLoadContext.cs (core) SqlConnectionFactory SqlClient  
SqlConnectionPoolGroupProviderInfo.cs #1323 SqlConnectionPoolGroupProviderInfo SqlClient  
SqlConnectionPoolKey.cs #1292 SqlConnectionPoolKey SqlClient  
SqlConnectionString.cs #1329 #1359 DEFAULT KEY SYNONYM TYPESYSTEMVERSION TRANSACTIONBINDING SqlClient  1
SqlConnectionString.cs SqlConnectionString.NetCoreApp.cs (core) #1329 #1359 SqlConnectionString SqlClient  
SqlConnectionStringBuilder.cs #1349 SqlConnectionStringBuilder SqlClient  
SqlDataAdapter.cs #1295 SqlDataAdapter    
SqlDataReader.cs #1309 SqlDataReader SqlClient  
SqlDelegatedTransaction.cs SqlDelegatedTransaction.NetCoreApp.cs (core) SqlDelegatedTransaction.NetStandard.cs (core) SqlDelegatedTransaction SqlClient  
SqlDependency.cs #1299 SqlDependency SqlClient  
SqlDependencyListener.cs #1308 SqlDependencyProcessDispatcher SqlClient  
SqlDependencyUtils.cs #1370 SqlDependencyUtils.AppDomain.cs (core) SqlDependencyUtils.AssemblyLoadContext.cs (core) SqlDependencyPerAppDomainDispatcher SqlClient  
SqlEnums.cs #1317 MetaType TdsDateTime SqlClient  
SqlError.cs #1322 SqlError SqlClient  
SqlErrorCollection.cs #1305 SqlErrorCollection SqlClient  
SqlException.cs #1300 SqlException SqlClient  
SqlInfoMessageEvent.cs #1311 SqlInfoMessageEventArgs SqlClient  
SqlInternalConnection.cs #1598 SqlInternalConnection SqlClient  
SqlInternalConnectionTds.cs SqlInternalConnectionTds SessionStateRecord SessionData ServerInfo SqlClient  
SqlInternalTransaction.cs #1346 SqlInternalTransaction SqlClient  
Sqlmetadatafactory.cs #1315 sqlmetadatafactory SqlClient  
SqlNotificationEventArgs.cs #1314 SqlNotificationEventArgs SqlClient  
SqlParameter.cs #1354 DataFeed StreamDataFeed TextDataFeed XmlDataFeed SqlParameter SqlClient  
SqlQueryMetadataCache.cs #1316 SqlQueryMetadataCache SqlClient  
SqlReferenceCollection.cs #1303 SqlReferenceCollection SqlClient  
SqlSequentialStream.cs #1345 SqlSequentialStream SqlClient  
SqlSequentialTextReader.cs #1343 SqlSequentialTextReader SqlUnicodeEncoding SqlClient  
SqlStream.cs #1337 SqlStream SqlCachedStream SqlStreamingXml SqlClient  
SqlTransaction.cs #1353 SqlTransaction SqlClient  
SqlUtil.cs #2503 #2533 AsyncHelper SQL SQLMessage SqlServerEscapeHelper SysTxForGlobalTransactions SqlClient  
TdsEnums.cs #1369 TdsEnums ActiveDirectoryAuthentication ParsingErrorState SniContext SqlConnectionColumnEncryptionSetting SqlConnectionOverrides SqlCommandColumnEncryptionSetting SqlConnectionAttestationProtocol SqlConnectionIPAddressPreference SqlAuthenticationMethod TransparentNetworkResolutionState DescribeParameterEncryptionResultSet1 DescribeParameterEncryptionResultSet2 DescribeParameterEncryptionResultSet3 SqlClient  
TdsParser.cs TdsParser.NetCoreApp.cs (core) TdsParser.NetStandard.cs (core) TdsParser.RegisterEncoding.cs (core) TdsParser.Unix.cs (core) TdsParser.Windows.cs (core) TdsParser SqlClient  
TdsParserSafeHandles.cs #1604 SNILoadHandle SNIHandle SNIPacket WritePacketCache SqlClient  
TdsParserSessionPool.cs #1595 TdsParserSessionPool SqlClient  
TdsParserStateObject.cs #1520, #1844, #2168, #2254, #2302 TdsParserStateObject LastIOTimer SqlClient  
TdsParserStaticMethods.cs #1588 TdsParserStaticMethods SqlClient  
SqlFileStream.cs (fx) SqlFileStream.Windows.cs (core) SqlFileStream SqlTypes  
@DavoudEshtehari DavoudEshtehari added the ➕ Code Health Changes related to source code improvements label Sep 11, 2021
@Wraith2
Copy link
Contributor

Wraith2 commented Sep 11, 2021

I think KeyConverter is done. There isn't a way to merge further for two reasons, 1) netstandard doesn't contain elliptical curve 2) netcore and netfx instantiate crypto providers in entirely different ways that I couldn't abstract any further.

SqlBuffer is very close to being done the remaining differences are because there is allocation free guid support in netcore that isn't in netfx. This means that SqlDataReader changes need to be ported to add that feature on netfx.

Some classes like TdsParser, TdsParserStateObject, SqlDataReader, SqlCommand are very large and I don't think we can do in a single PR, it would be impossible to review. I believe the way to do those types is a many small PR's which take identical functionality from both into a new shared version of the file slowly reducing each project specific file to the parts which are different and then those can be thoroughly reviewed.

@DavoudEshtehari
Copy link
Member Author

Thanks for the comments.
Regarding the KeyConverter, I think we could extract the behavior of the class in the lowest possible abstraction.
I completely agree with keeping the PRs as simple as possible for the sake of review. Based on your idea, the above table doesn't mean each file or type should be merged in a single PR.

@Wraith2
Copy link
Contributor

Wraith2 commented Sep 24, 2021

Looking at some of the merged from @lcheunglci I thought it might be useful to write down some of my knowledge and methodology used in my merges. From what I've gathered:

The nextfx codebase was forked at some point and that fork had a managed implementation of the network interface written so that it could be used on linux for netcore. This means that this codebase now has managed and native versions of the Sql Network Interface (SNI) in the netcore codebase and they are switched out depending on the platform that you restore the nuget package for. You can also force the use of managed network in windows with an appcontext switch. This mostly makes a difference in the core of TdsParser and TdsParserStateObject.

After netcore was forked the codebase was cleaned up a bit. So in general netcore is newer than netfx. However, changes and fixes may have been made to the netcore and netfx codebases independently so there's no guarantee that either was one better than the other they can both contain better versions of any particular function.

The netfx codebase is very very old, it was in the original 1.0 release of netfx and it hasn't always been updated to use the latest features. An example of this is the pool key derivation mechanism on netfx, it uses direct api calls to windows security apis because the managed equivalents were not available or not know to be usable at the time of writing.

This means that any change can be old or new and come from any version of the source code. To merge them you have to try to work out if they are functionally identical or equivalent enough that the difference cannot be observed by users up to and including timing and ordering of operations. This can get complicated and time consuming.

Style between the two codebases is highly variable. In general when merging a file it's a good idea to turn on the compiler Info messages and look through all the possible refactoring options is gives you. You don't have to take all the suggestions just take a look at them and make the code feel like it has the same style as some of the already merged components. The objective is to work towards a coherently styled single codebase where naming and formatting are easy to understand between most files.

@lcheunglci
Copy link
Contributor

Thanks @Wraith2 for your insight. I'll keep that in mind when I'm doing the code base merges. I'm currently starting small particularly focusing on the simpler code merges with the least conflicts before I look at the bigger ones. Your feedback and suggestions are much appreciated.

@lcheunglci
Copy link
Contributor

While I was looking into SqlReferenceCollection.cs in PR #1303 , I noticed a dependency on SqlInternalConnection.cs which I've have merge locally, but noticed another dependency on SqlDataReader.cs, which I also have merged locally. However, after a conversation with @cheenamalhotra, she mentioned there was a change to SqlDataReader.cs in #1019 , so I decided to put that on hold until that PR is approved and merged. In case someone else decided to merge SqlDataReader.cs and/or SqlInternalConnection.cs, I thought I'd mention it here to let you know that the work is in progress.

Kaur-Parminder added a commit to Kaur-Parminder/SqlClient that referenced this issue Oct 4, 2021
Code merge for dotnet#1261 Issue for SmiXetterAccessMap class. Added the common code to .Common.cs class.
@JRahnama JRahnama removed this from In progress in SqlClient v4.0 Nov 25, 2021
@JRahnama JRahnama added this to In Progress in SqlClient issues Nov 25, 2021
@Wraith2
Copy link
Contributor

Wraith2 commented Dec 23, 2021

I think some of the classes in TdsParserHelperClasses should be split out into their own files. Specifically _SqlRPC _SqlMetaData, _SqlMetaDataSet and anything else that is has methods of it's own, I think classes which are just used as DTO's are probalby fine collected together. I'd also like to get rid of the _ prefixes on those classes.

@ErikEJ
Copy link
Contributor

ErikEJ commented Jun 4, 2022

@DavoudEshtehari SqlEnums.cs was moved to shared in #1317
SqlClientMetaDataCollectionNames.cs was moved to shared in #1287

@edwardneal
Copy link
Contributor

The PR referenced above (#2369) covers the merge of SqlClientFactory, but I think I can also handle a few others. Some of these have side-effects though:

  • SqlColumnEncryptionEnclaveProvider: these files are identical, and I'll just merge them. This is the simplest case
  • SqlColumnEncryption[Csp/Cng/CertificateStore]Provider: these files are nearly identical, and are also a simple merge. However, I'd also like to enable Unix support, since the underlying cryptography library supports these
  • AlwaysEncryptedKeyConverter: the .NET Core implementation is different to the .NET Framework version, but might be able to replace it
  • Everything in AlwaysEncryptedHelperClasses.cs: implementations are identical
  • Almost everything in TdsHelperClasses.cs: once AlwaysEncryptedHelperClasses are addressed, the implementations are almost identical

This'd need some additional testing, but I think this would enable Always Encrypted support across Windows and Linux.

If I get time, I might be able to look at DbConnectionPool, DbConnectionClosed, DbConnectionInternal, DbConnectionFactory, which are also very similar between the two projects.

@Wraith2
Copy link
Contributor

Wraith2 commented Feb 26, 2024

When I worked on the encryption portions of the codebases I found that they could not be merged because netstandard does not have one of the required crypto primitives. This forces the use of platform specific apis and ifdefs. There may be a comment in the code but i'm sure if you look up the PR's around it you should find the description in my PR.

@ErikEJ
Copy link
Contributor

ErikEJ commented Feb 27, 2024

@Wraith2 So removing netstandard support will improve the abaility to merge code?

@edwardneal
Copy link
Contributor

edwardneal commented Feb 27, 2024

I think I see the PR you're talking about @Wraith2 (#1022), thanks for that. Nowadays, the main problem lies in the ECDiffieHellman class: the creation of an RSA instance from a key blob seems to have been replaced with a managed implementation.

Oddly, .NET Framework 4.6.1 (which implements .NET Standard 2.0) has this class. Other frameworks naturally implement it, so we could potentially have one code path for .NET Standard 2.1 and .NET Framework, then a PlatformNotSupportedException for everything else.

This means that it wouldn't support the platform versions below:

Platform Unsupported version Last release date Vendor supported
Mono < 6.4 6-Nov-2017 ?
Xamarin.iOS < 12.16 5-Aug-2019 No
Xamarin.Mac < 5.16 12-Sep-2019 No (now part of .NET 6 which is supported)
Xamarin.Android < 10.0 5-Sep-2019 No
UWP All ? ?
Unity < 2021.2 25-Oct-2021 No

I personally think it'd be justifiable not to explicitly add support for a platform that the vendors don't support themselves, but not adding anything for UWP is a pity. I don't think there's a way to include it though.

Naturally if SqlClient as a whole drops support for .NET Standard (2.0 or more broadly) then this problem becomes academic!

@JRahnama
Copy link
Member

@Wraith2 So removing netstandard support will improve the abaility to merge code?

it definitely will do and specifically NetStandard 2.0

@edwardneal
Copy link
Contributor

Just as an update on this: PRs #2369, #2376, #2383 and #2390 will merge SqlClientFactory, AlwaysEncryptedHelperClasses, TdsParserHelperClasses, AAsyncCallContext and DbConnectionPoolIdentity. They also lay the groundwork for the merge of SqlDataReader. I think I can also safely merge DbConnectionFactory, DbReferenceCollection, DbConnectionClosed, SqlAuthenticationProviderManager and SqlFileStream without raising too many eyebrows - the implementations are identical (or so close to identical that it barely matters.)

I can see the open issue and PR to terminate .NET Standard support, and I'll wait for this to be merged before dealing with the various encryption/enclave providers.

In one situation, specific functionality will need to be locked behind conditional compilation: the .NET Framework's MDS supports the Context Connection statement, which is used when it's running inside the SQL Server process as part of its CLR integration. By definition, .NET Core will never support this particular integration, and if I'm understanding the documentation correctly, SQL Server Language Extensions is out-of-process and thus wouldn't use it either. I'll wait to see what the supported platforms for MDS will end up being - if it won't support .NET Framework at all, we don't need it (or any of the auxiliary classes/functionality it brings.)

This leaves the more complicated cases, where functionality and support have diverged. So far I've come across a few of these:

  • MDS has differing connectivity capabilities for SQL Server. The .NET Core library can connect to SQL 2005+, while the .NET Framework library can also connect to SQL 7.0 and 2000. While it's possible to maintain that difference, I can see an earlier issue (Connection to SQL Server 2000 fails with unhelpful message; missing supported versions documentation #1841) which indicates that we don't support it. I don't want to raise a PR removing support without confirmation that this is the right thing to do.
  • The .NET Framework MDS library will try to create a LocalDB instance before connecting to it, while the .NET Core library just tries to connect to it.
  • .NET Core and .NET Framework expose statistics in different ways - Core uses event counters, Framework uses performance counters. This'll need an thin translation layer, since it'll need to be exposed as metrics for another issue.

Once there's the .NET Standard PR is implemented and there's nothing more I can merge, I'll take another look at these situations and see if they're as difficult as they look.

I'm not planning to look at TdsParser, SqlCommand or SqlConnection any time soon. These probably need someone with a much better understanding of the library's history than me.

@edwardneal
Copy link
Contributor

edwardneal commented May 16, 2024

@DavoudEshtehari SqlClientFactory has been merged in #2369. A lot of the other merge PRs pre-date the removal of support for .NET Standard - I'll bring these up to date as they're prioritised and reviewed.

In the wake of that removal, #2501 merges three of the four SqlColumnEncryptionKeyStoreProvider derivatives. These classes are almost identical between .NET Core and .NET Framework.

The remaining derived class is SqlColumnEncryptionCertificateStoreProvider, which is a little more complex: the .NET Framework version uses RSACryptoServiceProvider and directly accesses the private keys of certificates, while the .NET Core version uses the GetRSAPrivateKey extension method. I'll merge the class once I've tested with both CAPI and CNG keys.

Once #2501 and the extra PR (edit: #2521) have been merged, there'll be room for Unix support for Always Encrypted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
➕ Code Health Changes related to source code improvements
Projects
SqlClient issues
In Progress
Development

No branches or pull requests

6 participants